]> source.dussan.org Git - vaadin-framework.git/commitdiff
Refine handling of null and empty URI fragments (#12207)
authorLeif Åstrand <leif@vaadin.com>
Fri, 2 Aug 2013 07:20:40 +0000 (10:20 +0300)
committerLeif Åstrand <leif@vaadin.com>
Fri, 2 Aug 2013 07:20:46 +0000 (10:20 +0300)
Change-Id: Ie133694b010a586c6336e9b04be7bcd94d2525e9

client/src/com/vaadin/client/ui/ui/UIConnector.java
server/src/com/vaadin/server/Page.java
uitest/src/com/vaadin/tests/components/ui/UriFragmentTest.html
uitest/src/com/vaadin/tests/components/ui/UriFragmentTest.java

index 45b0a7ab9d4d4a77af3471a9830a58acb9a58989..c6d2e1436bbfd11ea54d9cc4248f1e95799f32ca 100644 (file)
@@ -40,6 +40,7 @@ import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.History;
 import com.google.gwt.user.client.Timer;
 import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.Window.Location;
 import com.google.gwt.user.client.ui.RootPanel;
 import com.google.gwt.user.client.ui.Widget;
 import com.google.web.bindery.event.shared.HandlerRegistration;
@@ -352,14 +353,30 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
         if (uidl.hasAttribute(UIConstants.LOCATION_VARIABLE)) {
             String location = uidl
                     .getStringAttribute(UIConstants.LOCATION_VARIABLE);
+            String newFragment;
+
             int fragmentIndex = location.indexOf('#');
             if (fragmentIndex >= 0) {
                 // Decode fragment to avoid double encoding (#10769)
-                getWidget().currentFragment = URL.decodePathSegment(location
+                newFragment = URL.decodePathSegment(location
                         .substring(fragmentIndex + 1));
+
+                if (newFragment.isEmpty()
+                        && Location.getHref().indexOf('#') == -1) {
+                    // Ensure there is a trailing # even though History and
+                    // Location.getHash() treat null and "" the same way.
+                    Location.assign(Location.getHref() + "#");
+                }
+            } else {
+                // No fragment in server-side location, but can't completely
+                // remove the browser fragment since that would reload the page
+                newFragment = "";
             }
-            if (!getWidget().currentFragment.equals(History.getToken())) {
-                History.newItem(getWidget().currentFragment, true);
+
+            getWidget().currentFragment = newFragment;
+
+            if (!newFragment.equals(History.getToken())) {
+                History.newItem(newFragment, true);
             }
         }
 
index 3656309be549aa5a5048a6f7dff0591413f7ad06..037d8e8352d2f0aae91e2c6d3311ba4f1949dd7e 100644 (file)
@@ -552,10 +552,11 @@ public class Page implements Serializable {
      * The fragment is the optional last component of a URI, prefixed with a
      * hash sign ("#").
      * <p>
-     * Passing <code>null</code> as <code>newFragment</code> clears the fragment
-     * (no "#" in the URI); passing an empty string sets an empty fragment (a
-     * trailing "#" in the URI.) This is consistent with the semantics of
-     * {@link java.net.URI}.
+     * Passing an empty string as <code>newFragment</code> sets an empty
+     * fragment (a trailing "#" in the URI.) Passing <code>null</code> if there
+     * is already a non-null fragment will leave a trailing # in the URI since
+     * removing it would cause the browser to reload the page. This is not fully
+     * consistent with the semantics of {@link java.net.URI}.
      * 
      * @param newUriFragment
      *            The new fragment.
@@ -570,6 +571,11 @@ public class Page implements Serializable {
      */
     public void setUriFragment(String newUriFragment, boolean fireEvents) {
         String oldUriFragment = location.getFragment();
+        if (newUriFragment == null && getUriFragment() != null) {
+            // Can't completely remove the fragment once it has been set, will
+            // instead set it to the empty string
+            newUriFragment = "";
+        }
         if (newUriFragment == oldUriFragment
                 || (newUriFragment != null && newUriFragment
                         .equals(oldUriFragment))) {
index bcb9f52afe86e0f32de9aaf2ed056d45a27ea22d..ba24b55f64b4169d6cb12d6421c359d1d1a689ff 100644 (file)
        <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td>
        <td>Current URI fragment: test</td>
 </tr>
-
+<!--Open other URL in between to ensure the page is loaded again (testbench doesn't like opening a URI that only changes the fragment)-->
+<tr>
+       <td>open</td>
+       <td>/run/</td>
+       <td></td>
+</tr>
+<tr>
+       <td>open</td>
+       <td>/run/com.vaadin.tests.components.ui.UriFragmentTest?restartApplication</td>
+       <td></td>
+</tr>
+<!--Empty initial fragment-->
+<tr>
+       <td>assertText</td>
+       <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+       <td>No URI fragment set</td>
+</tr>
+<tr>
+       <td>click</td>
+       <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td>
+       <td></td>
+</tr>
+<!--Still no # after setting to null-->
+<tr>
+       <td>assertText</td>
+       <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+       <td>No URI fragment set</td>
+</tr>
+<tr>
+       <td>click</td>
+       <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+       <td></td>
+</tr>
+<!--Empty # is added when setting to ""-->
+<tr>
+       <td>assertText</td>
+       <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+       <td>Current URI fragment:</td>
+</tr>
+<tr>
+       <td>click</td>
+       <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]</td>
+       <td></td>
+</tr>
+<tr>
+       <td>assertText</td>
+       <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+       <td>Current URI fragment: test</td>
+</tr>
+<tr>
+       <td>click</td>
+       <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td>
+       <td></td>
+</tr>
+<!--Setting to null when there is a fragment actually sets it to #-->
+<tr>
+       <td>assertText</td>
+       <td>vaadin=runcomvaadintestscomponentsuiUriFragmentTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+       <td>Current URI fragment:</td>
+</tr>
 </tbody></table>
 </body>
 </html>
index 2172b00ee38c7c4e7aba6eab484dd5e589034763..bfd784280aeb350ef094144419177ccde8ef78b5 100644 (file)
@@ -29,6 +29,21 @@ public class UriFragmentTest extends AbstractTestUI {
                         getPage().setUriFragment("test");
                     }
                 }));
+
+        addComponent(new Button("Navigate to #", new Button.ClickListener() {
+            @Override
+            public void buttonClick(ClickEvent event) {
+                getPage().setUriFragment("");
+            }
+        }));
+
+        addComponent(new Button("setUriFragment(null)",
+                new Button.ClickListener() {
+                    @Override
+                    public void buttonClick(ClickEvent event) {
+                        getPage().setUriFragment(null);
+                    }
+                }));
     }
 
     private void updateLabel() {