소스 검색

Bottom component click scroll up the parent panel in a window (#12943)

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: I79eafd1f9500c2e4c10dadbfc7100608c0732e04
tags/7.3.0.rc1
Bogdan Udrescu 10 년 전
부모
커밋
9b19675dff

+ 96
- 0
WebContent/html-tests/BottomComponentScrollsUp.html 파일 보기

@@ -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>

+ 0
- 1
client/src/com/vaadin/client/ApplicationConnection.java 파일 보기

@@ -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;

+ 18
- 0
client/src/com/vaadin/client/Util.java 파일 보기

@@ -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.
*

+ 3
- 20
client/src/com/vaadin/client/ui/VScrollTable.java 파일 보기

@@ -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);

+ 30
- 60
client/src/com/vaadin/client/ui/VWindow.java 파일 보기

@@ -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) {

+ 2
- 8
client/src/com/vaadin/client/ui/table/TableConnector.java 파일 보기

@@ -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);

+ 103
- 0
uitest/src/com/vaadin/tests/components/window/BottomComponentScrollsUp.java 파일 보기

@@ -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;
}

}

+ 71
- 0
uitest/src/com/vaadin/tests/components/window/BottomComponentScrollsUpTest.java 파일 보기

@@ -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");
}
}

Loading…
취소
저장