From cdb9a49bd542fe28ed29c52b90ee9875e2556f67 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Tue, 10 Sep 2013 15:36:51 +0300 Subject: Enable native scrolling in all iOS versions newer than 5, not just iOS 6 (#12324) Change-Id: I8f9ec7f34aefa5b48fd23f3f000f9455475edefa --- client/src/com/vaadin/client/BrowserInfo.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/BrowserInfo.java b/client/src/com/vaadin/client/BrowserInfo.java index 5d588f6f8b..84b6f14c34 100644 --- a/client/src/com/vaadin/client/BrowserInfo.java +++ b/client/src/com/vaadin/client/BrowserInfo.java @@ -207,8 +207,8 @@ public class BrowserInfo { return prefix + OS_ANDROID; } else if (browserDetails.isIOS()) { String iosClass = prefix + OS_IOS; - if (isIOS6()) { - iosClass += " " + prefix + OS_IOS + "6"; + if (getOperatingSystemMajorVersion() == 5) { + iosClass += " " + prefix + OS_IOS + "5"; } return iosClass; } else if (browserDetails.isWindows()) { @@ -392,9 +392,9 @@ public class BrowserInfo { if (isAndroid() && isWebkit() && getWebkitVersion() >= 534) { return false; } - // iOS 6 Safari supports native scrolling; iOS 5 suffers from #8792 + // iOS 6+ Safari supports native scrolling; iOS 5 suffers from #8792 // TODO Should test other iOS browsers - if (isIOS6() && isWebkit()) { + if (isIOS() && isWebkit() && getOperatingSystemMajorVersion() >= 6) { return false; } return true; -- cgit v1.2.3 From cf796e281ec684c94117725ab27d4089859e0161 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Thu, 19 Sep 2013 14:23:46 +0300 Subject: Add v-iosN classname for all iOS versions instead of just N=6 (#12324) Change-Id: Id06cfab1404facd612aa470d82757ae6dfe71641 --- client/src/com/vaadin/client/BrowserInfo.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/BrowserInfo.java b/client/src/com/vaadin/client/BrowserInfo.java index 84b6f14c34..273964c889 100644 --- a/client/src/com/vaadin/client/BrowserInfo.java +++ b/client/src/com/vaadin/client/BrowserInfo.java @@ -207,10 +207,7 @@ public class BrowserInfo { return prefix + OS_ANDROID; } else if (browserDetails.isIOS()) { String iosClass = prefix + OS_IOS; - if (getOperatingSystemMajorVersion() == 5) { - iosClass += " " + prefix + OS_IOS + "5"; - } - return iosClass; + return iosClass + " " + iosClass + getOperatingSystemMajorVersion(); } else if (browserDetails.isWindows()) { return prefix + OS_WINDOWS; } else if (browserDetails.isLinux()) { -- cgit v1.2.3 From d9f204fda6b56429b6dfe2dda0b79203ff2ef99e Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Thu, 12 Sep 2013 10:13:12 +0300 Subject: PostLayoutListener javadocs (#12562) Change-Id: Icdc39630a8d48f87ca4765f4513c9871d49f5d76 --- .../src/com/vaadin/client/ui/PostLayoutListener.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/PostLayoutListener.java b/client/src/com/vaadin/client/ui/PostLayoutListener.java index d60360747c..3da2358b0c 100644 --- a/client/src/com/vaadin/client/ui/PostLayoutListener.java +++ b/client/src/com/vaadin/client/ui/PostLayoutListener.java @@ -15,6 +15,24 @@ */ package com.vaadin.client.ui; +import com.vaadin.client.ComponentConnector; +import com.vaadin.client.LayoutManager; + +/** + * Interface implemented by {@link ComponentConnector} implementations that want + * to know whenever a layout phase has ended. At the end of each layout phase, + * {@link LayoutManager} invokes the {@link #postLayout()} method for all + * registered component connectors implementing this interface. + * + * @since 7.0 + * @author Vaadin Ltd + */ public interface PostLayoutListener { + /** + * Method invoked by {@link LayoutManager} to notify the connector that a + * layout phase has ended. This method can be used to finalize internal + * layouting, but it is not allowed to change the its own external size or + * modify the conditions for any children. + */ public void postLayout(); } -- cgit v1.2.3 From c7aaa0413f63d938791e760b23fb3f609f285aa0 Mon Sep 17 00:00:00 2001 From: Jonatan Kronqvist Date: Fri, 20 Sep 2013 15:32:12 +0300 Subject: Don't try to cast a connector to Widget. Fixes #12619 Change-Id: I0fe98ca90ed3969f1af1be60668b4c1c561675eb --- .../com/vaadin/client/ui/dd/VTargetInSubtree.java | 4 +- uitest/src/com/vaadin/tests/dd/DnDOnSubtree.html | 51 ++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/dd/DnDOnSubtree.html (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/dd/VTargetInSubtree.java b/client/src/com/vaadin/client/ui/dd/VTargetInSubtree.java index e9061114aa..c3f56b410d 100644 --- a/client/src/com/vaadin/client/ui/dd/VTargetInSubtree.java +++ b/client/src/com/vaadin/client/ui/dd/VTargetInSubtree.java @@ -32,7 +32,7 @@ final public class VTargetInSubtree extends VAcceptCriterion { protected boolean accept(VDragEvent drag, UIDL configuration) { VTree tree = (VTree) VDragAndDropManager.get().getCurrentDropHandler() - .getConnector(); + .getConnector().getWidget(); TreeNode treeNode = tree.getNodeByKey((String) drag.getDropDetails() .get("itemIdOver")); if (treeNode != null) { @@ -53,4 +53,4 @@ final public class VTargetInSubtree extends VAcceptCriterion { return false; } -} \ No newline at end of file +} diff --git a/uitest/src/com/vaadin/tests/dd/DnDOnSubtree.html b/uitest/src/com/vaadin/tests/dd/DnDOnSubtree.html new file mode 100644 index 0000000000..844636cb02 --- /dev/null +++ b/uitest/src/com/vaadin/tests/dd/DnDOnSubtree.html @@ -0,0 +1,51 @@ + + + + + + + DnDOnSubtree + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
New Test
open/run/com.vaadin.tests.dd.DDTest8?restartApplication
dragvaadin=runcomvaadintestsddDDTest8::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTree[0]#n[3]11,8
dropvaadin=runcomvaadintestsddDDTest8::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTree[0]#n[6]34,9
mouseClick + vaadin=runcomvaadintestsddDDTest8::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTree[0]#n[5]/expand + 10,8
assertElementPresent + vaadin=runcomvaadintestsddDDTest8::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTree[0]#n[5]/n[0] +
+ + -- cgit v1.2.3 From d3261d77a45a24edcb4e77370e12c8e88c119d35 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Thu, 19 Sep 2013 16:42:50 +0300 Subject: Fixes issue with Table not scrolling completely to the end #12651 Made the Table notice if the user is trying to scroll to an item on the last "page" and in those cases actually scroll to that item, not just to the page's first item as it did before. Change-Id: I47df33c75aa9b7e4f9a5f4bd5daeb301028517e8 --- client/src/com/vaadin/client/ui/VScrollTable.java | 27 +++++---- server/src/com/vaadin/ui/Table.java | 32 +++++++++-- .../tests/components/table/ShowLastItem.html | 36 ++++++++++++ .../tests/components/table/ShowLastItem.java | 66 ++++++++++++++++++++++ 4 files changed, 143 insertions(+), 18 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/table/ShowLastItem.html create mode 100644 uitest/src/com/vaadin/tests/components/table/ShowLastItem.java (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index 3733ee204a..492730259a 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -176,6 +176,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, private int firstRowInViewPort = 0; private int pageLength = 15; private int lastRequestedFirstvisible = 0; // to detect "serverside scroll" + private int firstvisibleOnLastPage = -1; // To detect if the first visible + // is on the last page /** For internal use only. May be removed or replaced in the future. */ public boolean showRowHeaders = false; @@ -1111,8 +1113,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets, private ScheduledCommand lazyScroller = new ScheduledCommand() { @Override public void execute() { - int offsetTop = measureRowHeightOffset(firstvisible); - scrollBodyPanel.setScrollPosition(offsetTop); + if (firstvisibleOnLastPage > -1) { + scrollBodyPanel + .setScrollPosition(measureRowHeightOffset(firstvisibleOnLastPage)); + } else { + scrollBodyPanel + .setScrollPosition(measureRowHeightOffset(firstvisible)); + } + firstRowInViewPort = firstvisible; } }; @@ -1120,6 +1128,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, public void updateFirstVisibleAndScrollIfNeeded(UIDL uidl) { firstvisible = uidl.hasVariable("firstvisible") ? uidl .getIntVariable("firstvisible") : 0; + firstvisibleOnLastPage = uidl.hasVariable("firstvisibleonlastpage") ? uidl + .getIntVariable("firstvisibleonlastpage") : -1; if (firstvisible != lastRequestedFirstvisible && scrollBody != null) { // received 'surprising' firstvisible from server: scroll there firstRowInViewPort = firstvisible; @@ -2150,18 +2160,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, isNewBody = false; - if (firstvisible > 0) { - // Deferred due to some Firefox oddities - Scheduler.get().scheduleDeferred(new Command() { - - @Override - public void execute() { - scrollBodyPanel - .setScrollPosition(measureRowHeightOffset(firstvisible)); - firstRowInViewPort = firstvisible; - } - }); - } + Scheduler.get().scheduleFinally(lazyScroller); if (enabled) { // Do we need cache rows diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java index bd2b7828de..32ed738697 100644 --- a/server/src/com/vaadin/ui/Table.java +++ b/server/src/com/vaadin/ui/Table.java @@ -426,6 +426,12 @@ public class Table extends AbstractSelect implements Action.Container, */ private int currentPageFirstItemIndex = 0; + /** + * Index of the "first" item on the last page if a user has used + * setCurrentPageFirstItemIndex to scroll down. -1 if not set. + */ + private int currentPageFirstItemIndexOnLastPage = -1; + /** * Holds value of property selectable. */ @@ -1477,12 +1483,14 @@ public class Table extends AbstractSelect implements Action.Container, } /* - * FIXME #7607 Take somehow into account the case where we want to - * scroll to the bottom so that the last row is completely visible even - * if (table height) / (row height) is not an integer. Reverted the - * original fix because of #8662 regression. + * If the new index is on the last page we set the index to be the first + * item on that last page and make a note of the real index for the + * client side to be able to move the scroll position to the correct + * position. */ + int indexOnLastPage = -1; if (newIndex > maxIndex) { + indexOnLastPage = newIndex; newIndex = maxIndex; } @@ -1494,6 +1502,20 @@ public class Table extends AbstractSelect implements Action.Container, currentPageFirstItemId = null; } currentPageFirstItemIndex = newIndex; + + if (needsPageBufferReset) { + /* + * The flag currentPageFirstItemIndexOnLastPage denotes a user + * set scrolling position on the last page via + * setCurrentPageFirstItemIndex() and shouldn't be changed by + * the table component internally changing the firstvisible item + * on lazy row fetching. Doing so would make the scrolling + * position not be updated correctly when the lazy rows are + * finally rendered. + */ + currentPageFirstItemIndexOnLastPage = indexOnLastPage; + } + } else { // For containers not supporting indexes, we must iterate the @@ -3447,6 +3469,8 @@ public class Table extends AbstractSelect implements Action.Container, if (getCurrentPageFirstItemIndex() != 0 || getPageLength() > 0) { target.addVariable(this, "firstvisible", getCurrentPageFirstItemIndex()); + target.addVariable(this, "firstvisibleonlastpage", + currentPageFirstItemIndexOnLastPage); } } diff --git a/uitest/src/com/vaadin/tests/components/table/ShowLastItem.html b/uitest/src/com/vaadin/tests/components/table/ShowLastItem.html new file mode 100644 index 0000000000..c9c93198fa --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/ShowLastItem.html @@ -0,0 +1,36 @@ + + + + + +New Test + + + + + + + + + + + + + + + + + + + + + + + + + + + +
New Test
open/run/com.vaadin.tests.components.table.ShowLastItem?restartApplication
clickvaadin=runcomvaadintestscomponentstableShowLastItem::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]
pause1000
screenCapturerow-20-fully-visible
+ + diff --git a/uitest/src/com/vaadin/tests/components/table/ShowLastItem.java b/uitest/src/com/vaadin/tests/components/table/ShowLastItem.java new file mode 100644 index 0000000000..6d6f744918 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/ShowLastItem.java @@ -0,0 +1,66 @@ +package com.vaadin.tests.components.table; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Table; + +public class ShowLastItem extends AbstractTestUI { + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + final Table table = new Table(); + table.setHeight("210px"); + + table.addContainerProperty("Col", String.class, ""); + + for (int i = 0; i < 20; i++) { + table.addItem(i).getItemProperty("Col") + .setValue("row " + String.valueOf(i)); + } + + Button addItemBtn = new Button("Add item", new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + Object itemId = "row " + table.getItemIds().size(); + + table.addItem(itemId).getItemProperty("Col") + .setValue(String.valueOf(itemId)); + + table.setCurrentPageFirstItemIndex(table.getItemIds().size() - 1); + } + }); + + addComponent(table); + addComponent(addItemBtn); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "Show last item in Table by using setCurrentPageFirstItemId"; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 12407; + } + +} -- cgit v1.2.3 From 8ce6565b3ee456db4f95b41568a8b31721a48cd6 Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Thu, 26 Sep 2013 15:59:55 +0300 Subject: Fixes normal drag and drop events (regression since 7.1) and html5 style D&D in IE10 (#12339) Change-Id: Ied4504406ebbeab6ff464fb239f7b3f5987fbbd9 --- client/src/com/vaadin/client/ui/VDragAndDropWrapper.java | 15 ++++++++++----- .../src/com/vaadin/client/ui/dd/VDragAndDropManager.java | 11 +++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/VDragAndDropWrapper.java b/client/src/com/vaadin/client/ui/VDragAndDropWrapper.java index 1c1173c295..ccd7e2758e 100644 --- a/client/src/com/vaadin/client/ui/VDragAndDropWrapper.java +++ b/client/src/com/vaadin/client/ui/VDragAndDropWrapper.java @@ -332,11 +332,16 @@ public class VDragAndDropWrapper extends VCustomComponent implements vaadinDragEvent.setCurrentGwtEvent(event); getDropHandler().dragOver(vaadinDragEvent); - String s = event.getEffectAllowed(); - if ("all".equals(s) || s.contains("opy")) { - event.setDropEffect("copy"); - } else { - event.setDropEffect(s); + try { + String s = event.getEffectAllowed(); + if ("all".equals(s) || s.contains("opy")) { + event.setDropEffect("copy"); + } else { + event.setDropEffect(s); + } + } catch (Exception e) { + // IE10 throws exception here in getEffectAllowed, ignore it, let + // drop effect be whatever it is } try { diff --git a/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java b/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java index b4cf008a38..b911c28a07 100644 --- a/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java +++ b/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java @@ -374,6 +374,17 @@ public class VDragAndDropManager { public void onPreviewNativeEvent( NativePreviewEvent event) { int typeInt = event.getTypeInt(); + if (typeInt == -1 + && event.getNativeEvent().getType() + .contains("MSPointer")) { + /* + * Ignore MSPointer events, until they are + * properly used (might improve usability on + * touch devices). + */ + return; + } + switch (typeInt) { case Event.ONMOUSEOVER: if (dragElement == null) { -- cgit v1.2.3 From a5795f346e077268eb77edef09d902fba57d5804 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Mon, 23 Sep 2013 16:51:42 +0300 Subject: Prefixes GET parameters in Liferay with portlet namespace #12602 Change-Id: I9939a7af83482e136ed0d146accdeec0cd9f10ea --- .../vaadin/client/ApplicationConfiguration.java | 17 +++++++++++++ .../com/vaadin/client/ApplicationConnection.java | 2 +- server/src/com/vaadin/server/VaadinPortlet.java | 29 +++++++++++++++++++--- .../communication/PortletBootstrapHandler.java | 11 ++++++++ .../com/vaadin/shared/ApplicationConstants.java | 4 +++ 5 files changed, 58 insertions(+), 5 deletions(-) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ApplicationConfiguration.java b/client/src/com/vaadin/client/ApplicationConfiguration.java index da8f521799..7a70080c7e 100644 --- a/client/src/com/vaadin/client/ApplicationConfiguration.java +++ b/client/src/com/vaadin/client/ApplicationConfiguration.java @@ -246,6 +246,23 @@ public class ApplicationConfiguration implements EntryPoint { ApplicationConstants.SERVICE_URL_PATH_AS_PARAMETER) == Boolean.TRUE; } + /** + * Return the name of the parameter used to to send data to the service url. + * This method should only be called if {@link #useServiceUrlPathParam()} is + * true. + * + * @since 7.1.6 + * @return The parameter name, by default v-resourcePath + */ + public String getServiceUrlParameterName() { + String prefix = getJsoConfiguration(id).getConfigString( + ApplicationConstants.SERVICE_URL_PARAMETER_NAMESPACE); + if (prefix == null) { + prefix = ""; + } + return prefix + ApplicationConstants.V_RESOURCE_PATH; + } + public String getRootPanelId() { return id; } diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 0d9c859ee8..4314602bc2 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -2994,7 +2994,7 @@ public class ApplicationConnection { if (!path.startsWith("/")) { path = '/' + path; } - String pathParam = ApplicationConstants.V_RESOURCE_PATH + "=" + String pathParam = conf.getServiceUrlParameterName() + "=" + URL.encodeQueryString(path); serviceUrl = addGetParameters(serviceUrl, pathParam); uidlUri = serviceUrl; diff --git a/server/src/com/vaadin/server/VaadinPortlet.java b/server/src/com/vaadin/server/VaadinPortlet.java index d86e5e6507..093a1c9152 100644 --- a/server/src/com/vaadin/server/VaadinPortlet.java +++ b/server/src/com/vaadin/server/VaadinPortlet.java @@ -422,16 +422,37 @@ public class VaadinPortlet extends GenericPortlet implements Constants, * @return A wrapped version of the PorletRequest */ protected VaadinPortletRequest createVaadinRequest(PortletRequest request) { - String portalInfo = request.getPortalContext().getPortalInfo() - .toLowerCase(); - if (portalInfo.contains("liferay")) { + if (isLiferay(request)) { return new VaadinLiferayRequest(request, getService()); - } else if (portalInfo.contains("gatein")) { + } else if (isGateIn(request)) { return new VaadinGateinRequest(request, getService()); } else { return new VaadinPortletRequest(request, getService()); } + } + /** + * Returns true if the portlet request is from Liferay. + * + * @param request + * @return True if Liferay, false otherwise + */ + private static boolean isLiferay(PortletRequest request) { + String portalInfo = request.getPortalContext().getPortalInfo() + .toLowerCase(); + return portalInfo.contains("liferay"); + } + + /** + * Returns true if the portlet request if from GateIn + * + * @param request + * @return True if GateIn, false otherwise + */ + private static boolean isGateIn(PortletRequest request) { + String portalInfo = request.getPortalContext().getPortalInfo() + .toLowerCase(); + return portalInfo.contains("gatein"); } private VaadinPortletResponse createVaadinResponse(PortletResponse response) { diff --git a/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java b/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java index 2458951ada..dd6d3c9283 100644 --- a/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java +++ b/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java @@ -31,6 +31,7 @@ import org.json.JSONObject; import com.vaadin.server.BootstrapHandler; import com.vaadin.server.PaintException; import com.vaadin.server.VaadinPortlet; +import com.vaadin.server.VaadinPortlet.VaadinLiferayRequest; import com.vaadin.server.VaadinPortletRequest; import com.vaadin.server.VaadinPortletResponse; import com.vaadin.server.VaadinRequest; @@ -98,6 +99,8 @@ public class PortletBootstrapHandler extends BootstrapHandler { JSONObject parameters = super.getApplicationParameters(context); VaadinPortletResponse response = (VaadinPortletResponse) context .getResponse(); + VaadinPortletRequest request = (VaadinPortletRequest) context + .getRequest(); MimeResponse portletResponse = (MimeResponse) response .getPortletResponse(); ResourceURL resourceURL = portletResponse.createResourceURL(); @@ -108,6 +111,14 @@ public class PortletBootstrapHandler extends BootstrapHandler { parameters .put(ApplicationConstants.SERVICE_URL_PATH_AS_PARAMETER, true); + // If we are running in Liferay then we need to prefix all parameters + // with the portlet namespace + if (request instanceof VaadinLiferayRequest) { + parameters.put( + ApplicationConstants.SERVICE_URL_PARAMETER_NAMESPACE, + response.getPortletResponse().getNamespace()); + } + return parameters; } } \ No newline at end of file diff --git a/shared/src/com/vaadin/shared/ApplicationConstants.java b/shared/src/com/vaadin/shared/ApplicationConstants.java index 104f3047a8..4b5dc9140b 100644 --- a/shared/src/com/vaadin/shared/ApplicationConstants.java +++ b/shared/src/com/vaadin/shared/ApplicationConstants.java @@ -49,6 +49,10 @@ public class ApplicationConstants implements Serializable { public static final String SERVICE_URL_PATH_AS_PARAMETER = "usePathParameter"; + // Denotes the namespace which parameters should be prefixed with when + // passed as GET parameters. Currently only used by Liferay. + public static final String SERVICE_URL_PARAMETER_NAMESPACE = "pathParameterNS"; + // Javadocs in ApplicationConfiguration should be updated if this is changed public static final String V_RESOURCE_PATH = "v-resourcePath"; -- cgit v1.2.3 From 478acb8e9aa7505cc6eacf219e87202191810a39 Mon Sep 17 00:00:00 2001 From: Juho Nurminen Date: Mon, 23 Sep 2013 13:17:41 +0300 Subject: Check modifiers when handling TabSheet hot keys. Fixes #12178 Change-Id: I685dbf2c22e3b160632b811652bf3ab52d3ef6dc --- client/src/com/vaadin/client/ui/VTabsheet.java | 18 ++++---- .../tabsheet/TabSheetHotKeysWithModifiers.java | 50 ++++++++++++++++++++++ 2 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/tabsheet/TabSheetHotKeysWithModifiers.java (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/VTabsheet.java b/client/src/com/vaadin/client/ui/VTabsheet.java index fe29e2ebc0..7dec62bde0 100644 --- a/client/src/com/vaadin/client/ui/VTabsheet.java +++ b/client/src/com/vaadin/client/ui/VTabsheet.java @@ -1115,14 +1115,16 @@ public class VTabsheet extends VTabsheetBase implements Focusable, if (event.getSource() instanceof Tab) { int keycode = event.getNativeEvent().getKeyCode(); - if (keycode == getPreviousTabKey()) { - selectPreviousTab(); - } else if (keycode == getNextTabKey()) { - selectNextTab(); - } else if (keycode == getCloseTabKey()) { - Tab tab = tb.getTab(activeTabIndex); - if (tab.isClosable()) { - tab.onClose(); + if (!event.isAnyModifierKeyDown()) { + if (keycode == getPreviousTabKey()) { + selectPreviousTab(); + } else if (keycode == getNextTabKey()) { + selectNextTab(); + } else if (keycode == getCloseTabKey()) { + Tab tab = tb.getTab(activeTabIndex); + if (tab.isClosable()) { + tab.onClose(); + } } } } diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetHotKeysWithModifiers.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetHotKeysWithModifiers.java new file mode 100644 index 0000000000..c0b30ff68d --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetHotKeysWithModifiers.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2013 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.tabsheet; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Label; +import com.vaadin.ui.TabSheet; + +public class TabSheetHotKeysWithModifiers extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + TabSheet tabSheet = new TabSheet(); + tabSheet.setWidth("500px"); + tabSheet.setHeight("500px"); + tabSheet.addTab(new Label("Tab 1"), "Tab 1").setClosable(true); + tabSheet.addTab(new Label("Tab 2"), "Tab 2").setClosable(true); + tabSheet.addTab(new Label("Tab 3"), "Tab 3").setClosable(true); + setContent(tabSheet); + } + + @Override + protected String getTestDescription() { + return "Hot keys (left and right arrow keys and the delete key) should be ignored when they are pressed simultaneously with modifier keys"; + } + + @Override + protected Integer getTicketNumber() { + return 12178; + } + +} -- cgit v1.2.3 From ffb33be8a15f3e82ca095901ca4fd2713eb229e6 Mon Sep 17 00:00:00 2001 From: Juho Nurminen Date: Tue, 1 Oct 2013 15:14:28 +0300 Subject: Update slider client-side state object on value change (#12676) Change-Id: Ief93d845e5498388072e05a0faff7ef2d29f1c77 --- .../vaadin/client/ui/slider/SliderConnector.java | 1 + .../tests/components/slider/SliderDisable.java | 81 ++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/components/slider/SliderDisable.java (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/slider/SliderConnector.java b/client/src/com/vaadin/client/ui/slider/SliderConnector.java index e6e3e0467d..71462d69f0 100644 --- a/client/src/com/vaadin/client/ui/slider/SliderConnector.java +++ b/client/src/com/vaadin/client/ui/slider/SliderConnector.java @@ -52,6 +52,7 @@ public class SliderConnector extends AbstractFieldConnector implements @Override public void onValueChange(ValueChangeEvent event) { + getState().value = event.getValue(); rpc.valueChanged(event.getValue()); } diff --git a/uitest/src/com/vaadin/tests/components/slider/SliderDisable.java b/uitest/src/com/vaadin/tests/components/slider/SliderDisable.java new file mode 100644 index 0000000000..ea29a1657c --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/slider/SliderDisable.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2013 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.slider; + +import java.io.IOException; + +import org.junit.Test; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.tests.tb3.MultiBrowserTest; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Slider; +import com.vaadin.ui.VerticalLayout; + +public class SliderDisable extends AbstractTestUI { + + public static class SliderDisableTest extends MultiBrowserTest { + @Test + public void disableSlider() throws IOException { + openTestURL(); + WebElement element = vaadinElement("/VVerticalLayout[0]/Slot[0]/VSlider[0]/domChild[2]/domChild[0]"); + new Actions(driver).dragAndDropBy(element, 112, 0).perform(); + compareScreen("enabled"); + vaadinElementById("disableButton").click(); + compareScreen("disabled"); + } + } + + @Override + protected void setup(VaadinRequest request) { + VerticalLayout content = new VerticalLayout(); + content.setMargin(true); + content.setSpacing(true); + + final Slider slider = new Slider(0, 5); + slider.setWidth(200, Unit.PIXELS); + slider.setValue(1.0D); + + Button disableButton = new Button("Disable slider"); + disableButton.setId("disableButton"); + disableButton.addClickListener(new ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + slider.setEnabled(false); + } + }); + + content.addComponent(slider); + content.addComponent(disableButton); + setContent(content); + } + + @Override + protected String getTestDescription() { + return "The apparent value of the slider should not change when the slider is disabled"; + } + + @Override + protected Integer getTicketNumber() { + return 12676; + } + +} -- cgit v1.2.3 From 5966f01b9f804621ac123792850b43e86399ec60 Mon Sep 17 00:00:00 2001 From: Fabian Lange Date: Thu, 12 Sep 2013 16:20:17 +0200 Subject: reduce reflow and calculation in VOverlay (#12566) the actual position of VOverlay is only required when a shim or shadow is used. Otherwise the calculation of its position causes unnecessary reflows. Change-Id: Id3915fe55c6b477f5d3ff01ee3a505014303d6d6 --- client/src/com/vaadin/client/ui/VOverlay.java | 71 ++++++++++++++------------- 1 file changed, 38 insertions(+), 33 deletions(-) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/VOverlay.java b/client/src/com/vaadin/client/ui/VOverlay.java index ced476f9dd..0e031e3d0d 100644 --- a/client/src/com/vaadin/client/ui/VOverlay.java +++ b/client/src/com/vaadin/client/ui/VOverlay.java @@ -248,10 +248,6 @@ public class VOverlay extends PopupPanel implements CloseHandler { return isShadowEnabled() && shadow.getParentElement() != null; } - private boolean isShimElementAttached() { - return shimElement != null && shimElement.hasParentElement(); - } - private void adjustZIndex() { setZIndex(Z_INDEX); } @@ -469,36 +465,51 @@ public class VOverlay extends PopupPanel implements CloseHandler { getOffsetWidth(); } - PositionAndSize positionAndSize = new PositionAndSize(getActualLeft(), - getActualTop(), getOffsetWidth(), getOffsetHeight()); + if (isShadowEnabled() || needsShimElement()) { + + PositionAndSize positionAndSize = new PositionAndSize( + getActualLeft(), getActualTop(), getOffsetWidth(), + getOffsetHeight()); + + // Animate the size + positionAndSize.setAnimationFromCenterProgress(progress); + + Element container = getElement().getParentElement().cast(); - // Animate the size - positionAndSize.setAnimationFromCenterProgress(progress); + if (isShadowEnabled()) { + updateShadowPosition(progress, zIndex, positionAndSize); + if (shadow.getParentElement() == null) { + container.insertBefore(shadow, getElement()); + sinkShadowEvents(); + } + } + + if (needsShimElement()) { + updateShimPosition(positionAndSize); + if (shimElement.getParentElement() == null) { + container.insertBefore(shimElement, getElement()); + } + } + } + } + private void updateShadowPosition(final double progress, String zIndex, + PositionAndSize positionAndSize) { // Opera needs some shaking to get parts of the shadow showing - // properly - // (ticket #2704) - if (BrowserInfo.get().isOpera() && isShadowEnabled()) { + // properly (ticket #2704) + if (BrowserInfo.get().isOpera()) { // Clear the height of all middle elements DOM.getChild(shadow, 3).getStyle().setProperty("height", "auto"); DOM.getChild(shadow, 4).getStyle().setProperty("height", "auto"); DOM.getChild(shadow, 5).getStyle().setProperty("height", "auto"); } - // Update correct values - if (isShadowEnabled()) { - updatePositionAndSize(shadow, positionAndSize); - DOM.setStyleAttribute(shadow, "zIndex", zIndex); - DOM.setStyleAttribute(shadow, "display", progress < 0.9 ? "none" - : ""); - } - if (needsShimElement()) { - updatePositionAndSize((Element) Element.as(getShimElement()), - positionAndSize); - } + updatePositionAndSize(shadow, positionAndSize); + DOM.setStyleAttribute(shadow, "zIndex", zIndex); + DOM.setStyleAttribute(shadow, "display", progress < 0.9 ? "none" : ""); // Opera fix, part 2 (ticket #2704) - if (BrowserInfo.get().isOpera() && isShadowEnabled()) { + if (BrowserInfo.get().isOpera()) { // We'll fix the height of all the middle elements DOM.getChild(shadow, 3) .getStyle() @@ -513,17 +524,11 @@ public class VOverlay extends PopupPanel implements CloseHandler { .setPropertyPx("height", DOM.getChild(shadow, 5).getOffsetHeight()); } + } - Element container = getElement().getParentElement().cast(); - // Attach to dom if not there already - if (isShadowEnabled() && !isShadowAttached()) { - container.insertBefore(shadow, getElement()); - sinkShadowEvents(); - } - if (needsShimElement() && !isShimElementAttached()) { - container.insertBefore(getShimElement(), getElement()); - } - + private void updateShimPosition(PositionAndSize positionAndSize) { + updatePositionAndSize((Element) Element.as(getShimElement()), + positionAndSize); } /** -- cgit v1.2.3 From 600f5f3238ecca22a8e7890d0656b0a23bd7dbba Mon Sep 17 00:00:00 2001 From: Yuriy Artamonov Date: Thu, 26 Sep 2013 11:37:42 +0400 Subject: Do not try to focus invisible components which not present in UIDL #12654 Change-Id: I365940e72d97426eceb408878bc8b24d7655de7c --- client/src/com/vaadin/client/ui/ui/UIConnector.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index c6d2e1436b..46b5f63180 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -319,6 +319,11 @@ public class UIConnector extends AbstractSingleComponentContainerConnector ComponentConnector paintable = (ComponentConnector) uidl .getPaintableAttribute("focused", getConnection()); + if (paintable == null) { + // Do not try to focus invisible components which not present in UIDL + return; + } + final Widget toBeFocused = paintable.getWidget(); /* * Two types of Widgets can be focused, either implementing -- cgit v1.2.3 From 0e9ff32598ed86d5f24a8bce5c5c898d81dc2c84 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Wed, 2 Oct 2013 16:33:41 +0300 Subject: Ported regression fixes in 6.8 for #12407 to 7.1 branch Change-Id: Ie46ab97fc1ff89dd241eec9182ed0f92164b754d --- client/src/com/vaadin/client/ui/VScrollTable.java | 32 ++++++++++++----------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index 492730259a..6e9e28ff25 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -1113,14 +1113,16 @@ public class VScrollTable extends FlowPanel implements HasWidgets, private ScheduledCommand lazyScroller = new ScheduledCommand() { @Override public void execute() { - if (firstvisibleOnLastPage > -1) { - scrollBodyPanel - .setScrollPosition(measureRowHeightOffset(firstvisibleOnLastPage)); - } else { - scrollBodyPanel - .setScrollPosition(measureRowHeightOffset(firstvisible)); + if (firstvisible > 0) { + firstRowInViewPort = firstvisible; + if (firstvisibleOnLastPage > -1) { + scrollBodyPanel + .setScrollPosition(measureRowHeightOffset(firstvisibleOnLastPage)); + } else { + scrollBodyPanel + .setScrollPosition(measureRowHeightOffset(firstvisible)); + } } - firstRowInViewPort = firstvisible; } }; @@ -1131,17 +1133,15 @@ public class VScrollTable extends FlowPanel implements HasWidgets, firstvisibleOnLastPage = uidl.hasVariable("firstvisibleonlastpage") ? uidl .getIntVariable("firstvisibleonlastpage") : -1; if (firstvisible != lastRequestedFirstvisible && scrollBody != null) { - // received 'surprising' firstvisible from server: scroll there - firstRowInViewPort = firstvisible; + // Update lastRequestedFirstvisible right away here // (don't rely on update in the timer which could be cancelled). lastRequestedFirstvisible = firstRowInViewPort; - /* - * Schedule the scrolling to be executed last so no updates to the - * rows affect scrolling measurements. - */ - Scheduler.get().scheduleFinally(lazyScroller); + // Only scroll if the first visible changes from the server side. + // Else we might unintentionally scroll even when the scroll + // position has not changed. + Scheduler.get().scheduleDeferred(lazyScroller); } } @@ -2160,7 +2160,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets, isNewBody = false; - Scheduler.get().scheduleFinally(lazyScroller); + if (firstvisible > 0) { + Scheduler.get().scheduleDeferred(lazyScroller); + } if (enabled) { // Do we need cache rows -- cgit v1.2.3 From 267a4cae6de31d143c3d8d1d8dd79d4616896603 Mon Sep 17 00:00:00 2001 From: Artem Godin Date: Wed, 2 Oct 2013 17:07:14 +0300 Subject: Fix OptionGroup elements losing focus on value change (#10451) The misbehavior was caused by VOptionGroup.buildOptions recreating associated panel on every change by removing and adding new elements. With this fix applied it tries to update existing elements, distinguishing them by assigned keys. It will recreate panel though if elements are reordered or new elements were added/removed. Change-Id: I1245b2ff30ce1932614c1eac37bd0131cbd29dd7 --- client/src/com/vaadin/client/ui/VOptionGroup.java | 67 +++++++++++++++------ .../OptionGroupRetainFocusKeyboardValueChange.html | 54 +++++++++++++++++ .../OptionGroupRetainFocusKeyboardValueChange.java | 70 ++++++++++++++++++++++ 3 files changed, 174 insertions(+), 17 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.html create mode 100644 uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.java (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/VOptionGroup.java b/client/src/com/vaadin/client/ui/VOptionGroup.java index a4c8b6733c..455c7669f5 100644 --- a/client/src/com/vaadin/client/ui/VOptionGroup.java +++ b/client/src/com/vaadin/client/ui/VOptionGroup.java @@ -95,11 +95,29 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, } /* - * Return true if no elements were changed, false otherwise. + * Try to update content of existing elements, rebuild panel entirely + * otherwise */ @Override public void buildOptions(UIDL uidl) { - panel.clear(); + /* + * In order to retain focus, we need to update values rather than + * recreate panel from scratch (#10451). However, the panel will be + * rebuilt (losing focus) if number of elements or their order is + * changed. + */ + HashMap keysToOptions = new HashMap(); + for (Map.Entry entry : optionsToKeys.entrySet()) { + keysToOptions.put(entry.getValue(), entry.getKey()); + } + ArrayList existingwidgets = new ArrayList(); + ArrayList newwidgets = new ArrayList(); + + // Get current order of elements + for (Widget wid : panel) { + existingwidgets.add(wid); + } + optionsEnabled.clear(); if (isMultiselect()) { @@ -110,7 +128,6 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, for (final Iterator it = uidl.getChildIterator(); it.hasNext();) { final UIDL opUidl = (UIDL) it.next(); - CheckBox op; String itemHtml = opUidl.getStringAttribute("caption"); if (!htmlContentAllowed) { @@ -124,32 +141,48 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, + Icon.CLASSNAME + "\" alt=\"\" />" + itemHtml; } - if (isMultiselect()) { - op = new VCheckBox(); - op.setHTML(itemHtml); - } else { - op = new RadioButton(paintableId, itemHtml, true); - op.setStyleName("v-radiobutton"); - } + String key = opUidl.getStringAttribute("key"); + CheckBox op = keysToOptions.get(key); + if (op == null) { + // Create a new element + if (isMultiselect()) { + op = new VCheckBox(); + } else { + op = new RadioButton(paintableId); + op.setStyleName("v-radiobutton"); + } + if (icon != null && icon.length() != 0) { + Util.sinkOnloadForImages(op.getElement()); + op.addHandler(iconLoadHandler, LoadEvent.getType()); + } - if (icon != null && icon.length() != 0) { - Util.sinkOnloadForImages(op.getElement()); - op.addHandler(iconLoadHandler, LoadEvent.getType()); + op.addStyleName(CLASSNAME_OPTION); + op.addClickHandler(this); + + optionsToKeys.put(op, key); } - op.addStyleName(CLASSNAME_OPTION); + op.setHTML(itemHtml); op.setValue(opUidl.getBooleanAttribute("selected")); boolean optionEnabled = !opUidl .getBooleanAttribute(OptionGroupConstants.ATTRIBUTE_OPTION_DISABLED); boolean enabled = optionEnabled && !isReadonly() && isEnabled(); op.setEnabled(enabled); optionsEnabled.add(optionEnabled); + setStyleName(op.getElement(), ApplicationConnection.DISABLED_CLASSNAME, !(optionEnabled && isEnabled())); - op.addClickHandler(this); - optionsToKeys.put(op, opUidl.getStringAttribute("key")); - panel.add(op); + + newwidgets.add(op); + } + + if (!newwidgets.equals(existingwidgets)) { + // Rebuild the panel, losing focus + panel.clear(); + for (Widget wid : newwidgets) { + panel.add(wid); + } } } diff --git a/uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.html b/uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.html new file mode 100644 index 0000000000..046cac0e30 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.html @@ -0,0 +1,54 @@ + + + + + + +OptionGroupRetainFocusKeyboardValueChange + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionGroupRetainFocusKeyboardValueChange
open/run/OptionGroupRetainFocusKeyboardValueChange?restartApplication
pressSpecialKeyvaadin=runOptionGroupRetainFocusKeyboardValueChange::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VOptionGroup[0]/domChild[0]/domChild[0]space
screenCapture
pressSpecialKeyvaadin=runOptionGroupRetainFocusKeyboardValueChange::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VOptionGroup[0]/domChild[0]/domChild[0]down
screenCapture
pressSpecialKeyvaadin=runOptionGroupRetainFocusKeyboardValueChange::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VOptionGroup[0]/domChild[1]/domChild[0]down
screenCapture
+ + diff --git a/uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.java b/uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.java new file mode 100644 index 0000000000..570a300cb3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2013 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.optiongroup; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.OptionGroup; + +/** + * Testcase for #10451 + * + * @author Vaadin Ltd + */ +public class OptionGroupRetainFocusKeyboardValueChange extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final OptionGroup optiongroup = new OptionGroup(); + optiongroup.addItem(1); + optiongroup.addItem(2); + optiongroup.addItem(3); + optiongroup.setItemCaption(1, "A"); + optiongroup.setItemCaption(2, "B"); + optiongroup.setItemCaption(3, "C"); + optiongroup.setImmediate(true); + + optiongroup.addValueChangeListener(new ValueChangeListener() { + + @Override + public void valueChange(ValueChangeEvent event) { + if (optiongroup.isSelected(2)) { + optiongroup.setItemCaption(1, "A+"); + } else if (optiongroup.isSelected(3)) { + optiongroup.removeItem(2); + optiongroup.addItem(2); + optiongroup.setItemCaption(2, "B"); + } + } + }); + + addComponent(optiongroup); + + optiongroup.focus(); + } + + @Override + protected String getTestDescription() { + return "OptionGroup should retain focus after it's value being changed with keyboard"; + } + + @Override + protected Integer getTicketNumber() { + return 10451; + } +} -- cgit v1.2.3 From 07ca622a6b2edcf7a253762cf222155bdf460a88 Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Fri, 27 Sep 2013 19:00:53 +0300 Subject: Fixes #12564 (HorizontalLayout breaks w/ alignment & error indicator) Removed some obsolete (hopefully!?) code doing some odd things with caption height calculation and some refactoring to make that part of code slightly more readable. Change-Id: I960e4a9eba0388281868f18a182c8788cedf08f9 --- .../AbstractOrderedLayoutConnector.java | 32 ++++---- ...orizontalLayoutFullsizeContentWithErrorMsg.java | 96 ++++++++++++++++++++++ 2 files changed, 111 insertions(+), 17 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/orderedlayout/HorizontalLayoutFullsizeContentWithErrorMsg.java (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java index e0dc0d51df..ec4307e50b 100644 --- a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java +++ b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java @@ -19,6 +19,7 @@ import java.util.List; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; @@ -611,13 +612,14 @@ public abstract class AbstractOrderedLayoutConnector extends LayoutManager layoutManager = getLayoutManager(); for (ComponentConnector child : getChildComponents()) { - Slot slot = getWidget().getSlot(child.getWidget()); + Widget childWidget = child.getWidget(); + Slot slot = getWidget().getSlot(childWidget); Element captionElement = slot.getCaptionElement(); - CaptionPosition pos = slot.getCaptionPosition(); + CaptionPosition captionPosition = slot.getCaptionPosition(); - Element childElement = child.getWidget().getElement(); - int h = layoutManager.getOuterHeight(childElement); - if (h == -1) { + int pixelHeight = layoutManager.getOuterHeight(childWidget + .getElement()); + if (pixelHeight == -1) { // Height has not yet been measured -> postpone actions that // depend on the max height return -1; @@ -625,14 +627,10 @@ public abstract class AbstractOrderedLayoutConnector extends boolean hasRelativeHeight = slot.hasRelativeHeight(); + boolean captionSizeShouldBeAddedtoComponentHeight = captionPosition == CaptionPosition.TOP + || captionPosition == CaptionPosition.BOTTOM; boolean includeCaptionHeight = captionElement != null - && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM); - if (!hasRelativeHeight && !includeCaptionHeight - && captionElement != null) { - String sHeight = childElement.getStyle().getHeight(); - includeCaptionHeight = (sHeight == null || !sHeight - .endsWith("%")); - } + && captionSizeShouldBeAddedtoComponentHeight; if (includeCaptionHeight) { int captionHeight = layoutManager @@ -643,16 +641,16 @@ public abstract class AbstractOrderedLayoutConnector extends // depend on the max height return -1; } - h += captionHeight; + pixelHeight += captionHeight; } if (!hasRelativeHeight) { - if (h > highestNonRelative) { - highestNonRelative = h; + if (pixelHeight > highestNonRelative) { + highestNonRelative = pixelHeight; } } else { - if (h > highestRelative) { - highestRelative = h; + if (pixelHeight > highestRelative) { + highestRelative = pixelHeight; } } } diff --git a/uitest/src/com/vaadin/tests/components/orderedlayout/HorizontalLayoutFullsizeContentWithErrorMsg.java b/uitest/src/com/vaadin/tests/components/orderedlayout/HorizontalLayoutFullsizeContentWithErrorMsg.java new file mode 100644 index 0000000000..25675e07c5 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/orderedlayout/HorizontalLayoutFullsizeContentWithErrorMsg.java @@ -0,0 +1,96 @@ +package com.vaadin.tests.components.orderedlayout; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.Point; +import org.openqa.selenium.WebElement; + +import com.vaadin.server.UserError; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.tests.tb3.MultiBrowserTest; +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.HorizontalLayout; +import com.vaadin.ui.TextField; + +public class HorizontalLayoutFullsizeContentWithErrorMsg extends AbstractTestUI { + + private static final String FIELD_ID = "f"; + private static final String BUTTON_ID = "b"; + private TextField tf; + + @Override + protected Integer getTicketNumber() { + return 12564; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + HorizontalLayout hl = new HorizontalLayout(); + hl.setWidth("500px"); + + tf = new TextField(); + tf.setId(FIELD_ID); + tf.setWidth("100%"); + hl.addComponent(tf); + hl.setExpandRatio(tf, 1); + hl.setComponentAlignment(tf, Alignment.MIDDLE_CENTER); + + Button toggleError = new Button("Toggle error"); + toggleError.setId(BUTTON_ID); + toggleError.addClickListener(new ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + tf.setComponentError(tf.getComponentError() == null ? new UserError( + "foo") : null); + } + }); + hl.addComponent(toggleError); + + addComponent(hl); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "TextField should remain at same level vertically, horizontally width should adjust to fit error indicator."; + } + + public static class TbTest extends MultiBrowserTest { + + @Test + public void test() { + openTestURL(); + WebElement element = getDriver().findElement(By.id(FIELD_ID)); + Point location = element.getLocation(); + + WebElement errorToggleButton = getDriver().findElement( + By.id(BUTTON_ID)); + + errorToggleButton.click(); + + Assert.assertEquals(location, element.getLocation()); + + errorToggleButton.click(); + + Assert.assertEquals(location, element.getLocation()); + + } + + } + +} -- cgit v1.2.3 From 633b4e858c31769f4b8848c934651da1d54b2721 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 12 Sep 2013 20:57:01 +0300 Subject: Prepare for Atmosphere Javascript 2.0 (#12241) * Atmosphere 2.0 has changed enableProtocol to default to true. * Reopening a connection in Atmosphere 2.0 is signalled through an onReopen event (not present at all in Atmosphere 1.0.x) Fix was backported from master Change-Id: I6ed258087a0b3a06440ab9d19b621560fa4f998f Merge: no --- .../communication/AtmospherePushConnection.java | 24 ++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java index 3cecb09dc1..8bddd78688 100644 --- a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java +++ b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java @@ -228,10 +228,26 @@ public class AtmospherePushConnection implements PushConnection { return config; } - protected void onOpen(AtmosphereResponse response) { - transport = response.getTransport(); + protected void onReopen(AtmosphereResponse response) { + VConsole.log("Push connection re-established using " + transport); + onConnect(response); + } + protected void onOpen(AtmosphereResponse response) { VConsole.log("Push connection established using " + transport); + onConnect(response); + } + + /** + * Called whenever a server push connection is established (or + * re-established). + * + * @param response + * + * @since 7.2 + */ + protected void onConnect(AtmosphereResponse response) { + transport = response.getTransport(); switch (state) { case CONNECT_PENDING: @@ -422,6 +438,7 @@ public class AtmospherePushConnection implements PushConnection { reconnectInterval: 5000, maxReconnectOnClose: 10000000, trackMessageLength: true, + enableProtocol: false, messageDelimiter: String.fromCharCode(@com.vaadin.shared.communication.PushConstants::MESSAGE_DELIMITER) }; }-*/; @@ -435,6 +452,9 @@ public class AtmospherePushConnection implements PushConnection { config.onOpen = $entry(function(response) { self.@com.vaadin.client.communication.AtmospherePushConnection::onOpen(*)(response); }); + config.onReopen = $entry(function(response) { + self.@com.vaadin.client.communication.AtmospherePushConnection::onReopen(*)(response); + }); config.onMessage = $entry(function(response) { self.@com.vaadin.client.communication.AtmospherePushConnection::onMessage(*)(response); }); -- cgit v1.2.3 From 503e5757bbac1a28c8987ecae9f75d271a61899b Mon Sep 17 00:00:00 2001 From: Artem Godin Date: Thu, 3 Oct 2013 15:47:08 +0300 Subject: Fix NullPointerException in logger when message is null (#12588) LogSection.publish and VConsole.log/VConsole.error methods now replace null message with an empty string ("") Change-Id: I735b51bce971ababe2557f1b6c317c01066bc03c --- client/src/com/vaadin/client/VConsole.java | 18 ++++++++++++++---- .../com/vaadin/client/debug/internal/LogSection.java | 6 ++++++ 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/VConsole.java b/client/src/com/vaadin/client/VConsole.java index 37ed8e6370..32eb206a70 100644 --- a/client/src/com/vaadin/client/VConsole.java +++ b/client/src/com/vaadin/client/VConsole.java @@ -41,25 +41,35 @@ public class VConsole { public static void log(String msg) { if (LogConfiguration.loggingIsEnabled(Level.INFO)) { - getLogger().log(Level.INFO, msg); + // Check for null, so no NullPointerException is generated when + // formatting (#12588) + getLogger().log(Level.INFO, msg == null ? "null" : msg); } } public static void log(Throwable e) { if (LogConfiguration.loggingIsEnabled(Level.INFO)) { - getLogger().log(Level.INFO, e.getMessage(), e); + // Check for null, so no NullPointerException is generated when + // formatting (#12588) + getLogger().log(Level.INFO, + e.getMessage() == null ? "" : e.getMessage(), e); } } public static void error(Throwable e) { if (LogConfiguration.loggingIsEnabled(Level.SEVERE)) { - getLogger().log(Level.SEVERE, e.getMessage(), e); + // Check for null, so no NullPointerException is generated when + // formatting (#12588) + getLogger().log(Level.SEVERE, + e.getMessage() == null ? "" : e.getMessage(), e); } } public static void error(String msg) { if (LogConfiguration.loggingIsEnabled(Level.SEVERE)) { - getLogger().log(Level.SEVERE, msg); + // Check for null, so no NullPointerException is generated when + // formatting (#12588) + getLogger().log(Level.SEVERE, msg == null ? "null" : msg); } } diff --git a/client/src/com/vaadin/client/debug/internal/LogSection.java b/client/src/com/vaadin/client/debug/internal/LogSection.java index 1e7524b56d..f792ec95be 100644 --- a/client/src/com/vaadin/client/debug/internal/LogSection.java +++ b/client/src/com/vaadin/client/debug/internal/LogSection.java @@ -73,6 +73,12 @@ public class LogSection implements Section { return; } + // If no message is provided, record.getMessage will be null and so + // the formatter.format will fail with NullPointerException (#12588) + if (record.getMessage() == null) { + record.setMessage(""); + } + Formatter formatter = getFormatter(); String msg = formatter.format(record); -- cgit v1.2.3 From d9f6dadfb41c2b618390edf8a05bbe78a8794e06 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Mon, 7 Oct 2013 12:37:50 +0300 Subject: Fixed Table range selection IE regression #12407 After fixes for #12407 the range selection did not work in the case where the selection start had previously been removed. This caused MultiSelectWithRemovedRow test to fail on IE. Change-Id: Iaa91cc6a3a310aedc80c4c2475fa8e94a30a5563 --- client/src/com/vaadin/client/ui/VScrollTable.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index 6e9e28ff25..9cec59a5a2 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -6110,7 +6110,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets, .next(); setRowFocus(endRow); } + } else if (!startRow.isSelected()) { + // The start row is no longer selected (probably removed) + // and so we select from above + startRow = (VScrollTableRow) scrollBody.iterator().next(); + setRowFocus(endRow); } + // Deselect previous items if so desired if (deselectPrevious) { deselectAll(); -- cgit v1.2.3 From 3cba6bf847df3fab77cec04dcd2586c76316fd74 Mon Sep 17 00:00:00 2001 From: Artem Godin Date: Mon, 7 Oct 2013 17:19:57 +0300 Subject: Rebuild OptionGroup on HtmlContentAllowed/Multiselect changes (#10451) Fixes regression with HtmlContent in Safari 5 and changing of Multiselect properties on the fly. Change-Id: I4a3820eba8d1c06460777340ea36b1df31b38983 --- client/src/com/vaadin/client/ui/VOptionGroup.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/VOptionGroup.java b/client/src/com/vaadin/client/ui/VOptionGroup.java index 455c7669f5..fee1c313f5 100644 --- a/client/src/com/vaadin/client/ui/VOptionGroup.java +++ b/client/src/com/vaadin/client/ui/VOptionGroup.java @@ -87,11 +87,16 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, /** For internal use only. May be removed or replaced in the future. */ public boolean htmlContentAllowed = false; + private boolean wasHtmlContentAllowed = false; + private boolean wasMultiselect = false; + public VOptionGroup() { super(CLASSNAME); panel = (Panel) optionsContainer; optionsToKeys = new HashMap(); optionsEnabled = new ArrayList(); + + wasMultiselect = isMultiselect(); } /* @@ -143,7 +148,11 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, String key = opUidl.getStringAttribute("key"); CheckBox op = keysToOptions.get(key); - if (op == null) { + + // Need to recreate object if isMultiselect is changed (#10451) + // OR if htmlContentAllowed changed due to Safari 5 issue + if ((op == null) || (htmlContentAllowed != wasHtmlContentAllowed) + || (isMultiselect() != wasMultiselect)) { // Create a new element if (isMultiselect()) { op = new VCheckBox(); @@ -184,6 +193,9 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, panel.add(wid); } } + + wasHtmlContentAllowed = htmlContentAllowed; + wasMultiselect = isMultiselect(); } @Override -- cgit v1.2.3 From 281fc4334881080a89c487b2d867d4643b667809 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 7 Oct 2013 18:53:53 +0300 Subject: Fixed incorrect logging (#12241) Change-Id: Icfe32a26f9069b7c5ed8160dba93b806754acf58 --- .../com/vaadin/client/communication/AtmospherePushConnection.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java index 8bddd78688..4bf12ca1f3 100644 --- a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java +++ b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java @@ -229,12 +229,14 @@ public class AtmospherePushConnection implements PushConnection { } protected void onReopen(AtmosphereResponse response) { - VConsole.log("Push connection re-established using " + transport); + VConsole.log("Push connection re-established using " + + response.getTransport()); onConnect(response); } protected void onOpen(AtmosphereResponse response) { - VConsole.log("Push connection established using " + transport); + VConsole.log("Push connection established using " + + response.getTransport()); onConnect(response); } -- cgit v1.2.3 From e1c38bf70c9bb563dbe7771c8713a94fd9e99836 Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Fri, 27 Sep 2013 15:07:48 +0300 Subject: Avoid obsolete calendar panel renderings to avoid various NPEs. (#12504,#12667) Change-Id: Ie0a9a8d9913116520b766062ebabdb771a76d1b6 --- .../src/com/vaadin/client/ui/VCalendarPanel.java | 24 +++-- .../ui/datefield/PopupDateFieldConnector.java | 9 +- .../tests/components/datefield/DateFieldTest.java | 103 +++++++++++++++++++++ 3 files changed, 121 insertions(+), 15 deletions(-) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/VCalendarPanel.java b/client/src/com/vaadin/client/ui/VCalendarPanel.java index 1f40298760..58e0448b5f 100644 --- a/client/src/com/vaadin/client/ui/VCalendarPanel.java +++ b/client/src/com/vaadin/client/ui/VCalendarPanel.java @@ -2215,11 +2215,13 @@ public class VCalendarPanel extends FocusableFlexTable implements * - the allowed range's start date */ public void setRangeStart(Date rangeStart) { - this.rangeStart = rangeStart; - if (initialRenderDone) { - // Dynamic updates to the range needs to render the calendar to - // update the element stylenames - renderCalendar(); + if (this.rangeStart != rangeStart) { + this.rangeStart = rangeStart; + if (initialRenderDone) { + // Dynamic updates to the range needs to render the calendar to + // update the element stylenames + renderCalendar(); + } } } @@ -2232,11 +2234,13 @@ public class VCalendarPanel extends FocusableFlexTable implements * - the allowed range's end date */ public void setRangeEnd(Date rangeEnd) { - this.rangeEnd = rangeEnd; - if (initialRenderDone) { - // Dynamic updates to the range needs to render the calendar to - // update the element stylenames - renderCalendar(); + if (this.rangeEnd != rangeEnd) { + this.rangeEnd = rangeEnd; + if (initialRenderDone) { + // Dynamic updates to the range needs to render the calendar to + // update the element stylenames + renderCalendar(); + } } } } diff --git a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java index 627478ebe5..f018caefa5 100644 --- a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java +++ b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java @@ -77,9 +77,6 @@ public class PopupDateFieldConnector extends TextualDateConnector { String oldLocale = getWidget().getCurrentLocale(); - boolean lastReadOnlyState = getWidget().isReadonly(); - boolean lastEnabledState = getWidget().isEnabled(); - getWidget().parsable = uidl.getBooleanAttribute("parsable"); super.updateFromUIDL(uidl, client); @@ -92,7 +89,8 @@ public class PopupDateFieldConnector extends TextualDateConnector { .getCurrentResolution()) { getWidget().calendar.setResolution(getWidget() .getCurrentResolution()); - if (getWidget().calendar.getDate() != null) { + if (getWidget().calendar.getDate() != null + && getWidget().getCurrentDate() != null) { getWidget().calendar.setDate((Date) getWidget() .getCurrentDate().clone()); // force re-render when changing resolution only @@ -101,7 +99,7 @@ public class PopupDateFieldConnector extends TextualDateConnector { } // Force re-render of calendar if locale has changed (#12153) - if (getWidget().getCurrentLocale() != oldLocale) { + if (!getWidget().getCurrentLocale().equals(oldLocale)) { getWidget().calendar.renderCalendar(); } @@ -113,6 +111,7 @@ public class PopupDateFieldConnector extends TextualDateConnector { .setFocusChangeListener(new FocusChangeListener() { @Override public void focusChanged(Date date) { + getWidget().updateValue(date); getWidget().buildDate(); Date date2 = getWidget().calendar.getDate(); diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldTest.java b/uitest/src/com/vaadin/tests/components/datefield/DateFieldTest.java index d92199a214..2a61e79f32 100644 --- a/uitest/src/com/vaadin/tests/components/datefield/DateFieldTest.java +++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldTest.java @@ -7,8 +7,17 @@ import java.util.Date; import java.util.LinkedHashMap; import java.util.Locale; +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.Dimension; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + import com.vaadin.shared.ui.datefield.Resolution; import com.vaadin.tests.components.abstractfield.AbstractFieldTest; +import com.vaadin.tests.tb3.MultiBrowserTest; import com.vaadin.ui.DateField; public class DateFieldTest extends AbstractFieldTest { @@ -140,4 +149,98 @@ public class DateFieldTest extends AbstractFieldTest { } }; + public static class Tb3DateFieldTests extends MultiBrowserTest { + + @Override + protected boolean isDebug() { + // run in debug to see js errors + return true; + } + + @Test + public void testMakingRequired() throws InterruptedException { + Thread.sleep(1000); + menu("Component"); + menuSub("State"); + menu("Required"); + assertNoErrorNotification(); + } + + private void assertNoErrorNotification() { + try { + getDriver().findElement( + By.xpath("//div[contains(@class, 'v-Notification') ]")); + Assert.fail("Error notification shown!"); + } catch (NoSuchElementException e) { + // As expected + } + } + + @Test + public void testValueAfterOpeningPopupInRequiredField() + throws InterruptedException { + Thread.sleep(1000); + menu("Component"); + menuSub("State"); + menu("Required"); + + menu("Component"); + menuSub("Features"); + menuSub("Resolution"); + menu("Month"); + + menu("Component"); + menuSub("Listeners"); + menu("Value change listener"); + + String inputtedValue = "2/12"; + getInput().sendKeys(inputtedValue); + + openPopup(); + closePopup(); + String actual = getInput().getAttribute("value"); + Assert.assertEquals(inputtedValue, actual); + assertNoErrorNotification(); + + } + + private void openPopup() throws InterruptedException { + Dimension size = getInput().getSize(); + new Actions(getDriver()).moveToElement(getInput(), 0, 0) + .moveByOffset(size.getWidth() + 5, size.getHeight() / 2) + .click(); + // This fails in Opera for some weird reason + // getDriver().findElement(By.className("v-datefield-button")).click(); + } + + private WebElement getInput() { + return getDriver().findElement(By.xpath("//input")); + } + + private void closePopup() { + getDriver().findElement(By.tagName("body")).click(); + } + + /** + * @since + * @param string + */ + private void menuSub(String string) { + getDriver().findElement( + By.xpath("//span[text() = '" + string + "']")).click(); + new Actions(getDriver()).moveByOffset(100, 0).build().perform(); + } + + /** + * @since + * @param string + */ + private void menu(String string) { + getDriver().findElement( + By.xpath("//span[text() = '" + string + "']")).click(); + + } + + } + } -- cgit v1.2.3 From 3e593b0949b2b26fdc89b2aa5e8e93b006a513d0 Mon Sep 17 00:00:00 2001 From: John Ahlroos Date: Tue, 1 Oct 2013 16:55:39 +0300 Subject: Focus selected row in Table #12540 Change-Id: Ic920f9cb11840a456a7c49746317eaccde1e1406 --- client/src/com/vaadin/client/ui/VScrollTable.java | 11 ++ .../table/TableMoveFocusWithSelection.java | 125 +++++++++++++++++++++ .../table/TableMoveFocusWithSelectionTest.java | 75 +++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelection.java create mode 100644 uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelectionTest.java (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index 9cec59a5a2..104cbbd5b9 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -1072,6 +1072,17 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } if (selected != row.isSelected()) { row.toggleSelection(); + + if (selected) { + if (focusedRow == null + || !selectedRowKeys.contains(focusedRow + .getKey())) { + // The focus is no longer on a selected row, + // move focus to first selected row + setRowFocus(row); + } + } + if (!isSingleSelectMode() && !selected) { // Update selection range in case a row is // unselected from the middle of a range - #8076 diff --git a/uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelection.java b/uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelection.java new file mode 100644 index 0000000000..20170efa13 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelection.java @@ -0,0 +1,125 @@ +/* + * Copyright 2000-2013 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.table; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import com.vaadin.event.LayoutEvents.LayoutClickEvent; +import com.vaadin.event.LayoutEvents.LayoutClickListener; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Table; +import com.vaadin.ui.VerticalLayout; + +public class TableMoveFocusWithSelection extends AbstractTestUI { + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + final Table t = new Table(); + t.setImmediate(true); + t.setId("test-table"); + t.setSizeFull(); + t.setSelectable(true); + t.addContainerProperty("layout", VerticalLayout.class, null); + t.addContainerProperty("string", String.class, null); + + for (int i = 0; i < 100; i++) { + t.addItem(i); + final VerticalLayout l = new VerticalLayout(); + l.setId("row-" + i); + l.setHeight(20, Unit.PIXELS); + l.setData(i); + l.addLayoutClickListener(new LayoutClickListener() { + @Override + public void layoutClick(LayoutClickEvent event) { + if (t.isMultiSelect()) { + Set values = new HashSet( + (Set) t.getValue()); + values.add(l.getData()); + t.setValue(values); + } else { + t.setValue(l.getData()); + } + } + }); + t.getContainerProperty(i, "layout").setValue(l); + t.getContainerProperty(i, "string").setValue("Item #" + i); + } + addComponent(t); + + // Select mode + Button toggleSelectMode = new Button( + t.isMultiSelect() ? "Press to use single select" + : "Press to use multi select"); + toggleSelectMode.setId("toggle-mode"); + toggleSelectMode.addClickListener(new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + t.setMultiSelect(!t.isMultiSelect()); + + event.getButton().setCaption( + t.isMultiSelect() ? "Press to use single select" + : "Press to use multi select"); + } + }); + + addComponent(toggleSelectMode); + + Button select5210 = new Button("Select row 5-10", + new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + t.setValue(Arrays.asList(5, 6, 7, 8, 9, 10)); + } + }); + select5210.setId("select-510"); + addComponent(select5210); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "Changing selection in single select mode should move focus"; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 12540; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelectionTest.java b/uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelectionTest.java new file mode 100644 index 0000000000..b38705eeb6 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelectionTest.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2013 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.table; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Tests if table focus is moved correctly to the selected item + * + * @since + * @author Vaadin Ltd + */ +public class TableMoveFocusWithSelectionTest extends MultiBrowserTest { + + @Test + public void selectUnfocusedTableAndAssumeSelectionGetsFocus() { + + openTestURL(); + + // Click on row 5 + getDriver().findElement(By.id("row-5")).click(); + + // Ensure row 5 gets focused + WebElement row5TableRow = getDriver().findElement( + By.xpath("//div[@id='row-5']/../../..")); + String row5StyleName = row5TableRow.getAttribute("class"); + assertTrue(row5StyleName.contains("v-table-focus")); + } + + @Test + public void focusShouldStayOnUserSelectedRowIfSelectionChangesServerSide() { + + openTestURL(); + + // Select multiselect + getDriver().findElement(By.id("toggle-mode")).click(); + + // Click on row 7 + getDriver().findElement(By.id("row-7")).click(); + + // Select row 5-10 server side + getDriver().findElement(By.id("select-510")).click(); + + // Ensure row 7 is still focused + WebElement row7TableRow = getDriver().findElement( + By.xpath("//div[@id='row-7']/../../..")); + String row7StyleName = row7TableRow.getAttribute("class"); + assertTrue(row7StyleName.contains("v-table-focus")); + } + + @Override + protected Class getUIClass() { + // FIXME Remove when this is done automatically + return TableMoveFocusWithSelection.class; + } +} -- cgit v1.2.3 From 1b7e40de9435f2584fe6c7f1b7f69cc448c16cc8 Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Fri, 4 Oct 2013 15:41:06 +0300 Subject: Only fetch rows if there are some (#11189) IE hacks cause calls to onScroll in situations where the cache row fetch logic is not working correctly (causes JS exception). This change has an optimization to pass this logic if there are no rows available and this way fixes the JS exception as well. Change-Id: I3425f3d75cad8b65e605638343b167abf7b48067 --- client/src/com/vaadin/client/ui/VScrollTable.java | 5 ++ .../vaadin/tests/components/table/EmptyTable.java | 58 ++++++++++++++++++++++ .../tests/components/table/EmptyTableTest.java | 44 ++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/components/table/EmptyTable.java create mode 100644 uitest/src/com/vaadin/tests/components/table/EmptyTableTest.java (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index 104cbbd5b9..0304acd590 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -6913,6 +6913,11 @@ public class VScrollTable extends FlowPanel implements HasWidgets, // fix footers horizontal scrolling tFoot.setHorizontalScrollPosition(scrollLeft); + if (totalRows == 0) { + // No rows, no need to fetch new rows + return; + } + firstRowInViewPort = calcFirstRowInViewPort(); if (firstRowInViewPort > totalRows - pageLength) { firstRowInViewPort = totalRows - pageLength; diff --git a/uitest/src/com/vaadin/tests/components/table/EmptyTable.java b/uitest/src/com/vaadin/tests/components/table/EmptyTable.java new file mode 100644 index 0000000000..d6c30efa5a --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/EmptyTable.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2013 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.table; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Table; + +public class EmptyTable extends AbstractTestUI { + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + Table table = new Table("Table"); + table.addContainerProperty("testColumn", String.class, null); + table.setPageLength(0); // disable paging + addComponent(table); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "Empty Table should not cause JS exception"; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 11189; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/table/EmptyTableTest.java b/uitest/src/com/vaadin/tests/components/table/EmptyTableTest.java new file mode 100644 index 0000000000..229dc23b9a --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/EmptyTableTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2013 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.table; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class EmptyTableTest extends MultiBrowserTest { + + @Test + public void test() { + setDebug(true); + openTestURL(); + + ensureNoErrors(); + } + + private void ensureNoErrors() { + try { + getDriver().findElement(By.className("v-Notification")); + } catch (NoSuchElementException e) { + return; + } + Assert.fail("Error notification was shown!"); + } + +} \ No newline at end of file -- cgit v1.2.3