]> source.dussan.org Git - vaadin-framework.git/commitdiff
Provide a way to disallow navigation to the same state twice (#12107).
authorDenis Anisimov <denis@vaadin.com>
Sun, 16 Nov 2014 13:41:33 +0000 (15:41 +0200)
committerAleksi Hietanen <aleksi@vaadin.com>
Thu, 23 Jun 2016 12:41:25 +0000 (15:41 +0300)
Change-Id: I10e2f2c63402f434ca038d380372a552996102b6

server/src/com/vaadin/navigator/Navigator.java
server/tests/src/com/vaadin/tests/server/navigator/NavigatorTest.java

index 82e8de920afb24ef06f3411f19d9e06b04d94b5b..390e2529061dde8636fbc5b67560b6e7f69ebe8b 100644 (file)
@@ -41,6 +41,7 @@ import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
 import com.vaadin.server.Page;
 import com.vaadin.server.Page.UriFragmentChangedEvent;
 import com.vaadin.server.Page.UriFragmentChangedListener;
+import com.vaadin.shared.util.SharedUtil;
 import com.vaadin.ui.Component;
 import com.vaadin.ui.ComponentContainer;
 import com.vaadin.ui.CssLayout;
@@ -543,18 +544,11 @@ public class Navigator implements Serializable {
      *             and no error view is registered
      */
     public void navigateTo(String navigationState) {
-        String longestViewName = null;
-        ViewProvider longestViewNameProvider = null;
+        ViewProvider longestViewNameProvider = getViewProvider(navigationState);
+        String longestViewName = longestViewNameProvider == null ? null
+                : longestViewNameProvider.getViewName(navigationState);
         View viewWithLongestName = null;
-        for (ViewProvider provider : providers) {
-            String viewName = provider.getViewName(navigationState);
-            if (null != viewName
-                    && (longestViewName == null || viewName.length() > longestViewName
-                            .length())) {
-                longestViewName = viewName;
-                longestViewNameProvider = provider;
-            }
-        }
+
         if (longestViewName != null) {
             viewWithLongestName = longestViewNameProvider
                     .getView(longestViewName);
@@ -570,7 +564,15 @@ public class Navigator implements Serializable {
                 parameters = navigationState
                         .substring(longestViewName.length() + 1);
             }
-            navigateTo(viewWithLongestName, longestViewName, parameters);
+            if (getCurrentView() == null
+                    || !SharedUtil
+                            .equals(getCurrentView(), viewWithLongestName)) {
+                navigateTo(viewWithLongestName, longestViewName, parameters);
+            } else {
+                updateNavigationState(new ViewChangeEvent(this,
+                        getCurrentView(), viewWithLongestName, longestViewName,
+                        parameters));
+            }
         } else {
             throw new IllegalArgumentException(
                     "Trying to navigate to an unknown state '"
@@ -986,8 +988,33 @@ public class Navigator implements Serializable {
     }
 
     /**
-     * Destroys the navigator and cleans it up. The method detaches the
-     * navigator from UI and removes all view change listeners.
+     * Get view provider that handles the given {@code state}.
+     * 
+     * @param state
+     *            state string
+     * @return suitable provider
+     */
+    private ViewProvider getViewProvider(String state) {
+        String longestViewName = null;
+        ViewProvider longestViewNameProvider = null;
+        for (ViewProvider provider : providers) {
+            String viewName = provider.getViewName(state);
+            if (null != viewName
+                    && (longestViewName == null || viewName.length() > longestViewName
+                            .length())) {
+                longestViewName = viewName;
+                longestViewNameProvider = provider;
+            }
+        }
+        return longestViewNameProvider;
+    }
+
+    /**
+     * Creates view change event for given {@code view}, {@code viewName} and
+     * {@code parameters}.
+     * 
+     * @since
+     * @return view change event
      */
     public void destroy() {
         stateManager.setNavigator(null);
index 0de804fa0b5442d65db5a0405ffa84fc4ff59a8a..a490202d68db5d2a2c38281d0bda57b27e70e41c 100644 (file)
@@ -24,6 +24,7 @@ import org.easymock.EasyMock;
 import org.easymock.IArgumentMatcher;
 import org.easymock.IMocksControl;
 import org.junit.Assert;
+import org.junit.Test;
 
 import com.vaadin.navigator.NavigationStateManager;
 import com.vaadin.navigator.Navigator;
@@ -314,7 +315,8 @@ public class NavigatorTest extends TestCase {
         // prepare mocks: what to expect
         manager.setNavigator(EasyMock.anyObject(Navigator.class));
 
-        EasyMock.expect(provider.getViewName("test1")).andReturn("test1");
+        EasyMock.expect(provider.getViewName("test1")).andReturn("test1")
+                .times(2);
         EasyMock.expect(provider.getView("test1")).andReturn(view1);
         EasyMock.expect(manager.getState()).andReturn("");
         view1.enter(eventParametersEqual(""));
@@ -322,7 +324,8 @@ public class NavigatorTest extends TestCase {
         manager.setState("test1");
         EasyMock.expect(manager.getState()).andReturn("test1");
 
-        EasyMock.expect(provider.getViewName("test2/")).andReturn("test2");
+        EasyMock.expect(provider.getViewName("test2/")).andReturn("test2")
+                .times(2);
         EasyMock.expect(provider.getView("test2")).andReturn(view2);
         EasyMock.expect(manager.getState()).andReturn("test1");
         view2.enter(eventParametersEqual(""));
@@ -331,7 +334,7 @@ public class NavigatorTest extends TestCase {
         EasyMock.expect(manager.getState()).andReturn("test2");
 
         EasyMock.expect(provider.getViewName("test1/params"))
-                .andReturn("test1");
+                .andReturn("test1").times(2);
         EasyMock.expect(provider.getView("test1")).andReturn(view1);
         EasyMock.expect(manager.getState()).andReturn("test2");
         view1.enter(eventParametersEqual("params"));
@@ -367,14 +370,15 @@ public class NavigatorTest extends TestCase {
         // prepare mocks: what to expect
         manager.setNavigator(EasyMock.anyObject(Navigator.class));
 
-        EasyMock.expect(provider.getViewName("test2")).andReturn("test2");
+        EasyMock.expect(provider.getViewName("test2")).andReturn("test2")
+                .times(2);
         EasyMock.expect(provider.getView("test2")).andReturn(view2);
         EasyMock.expect(manager.getState()).andReturn("view1");
         view2.enter(eventParametersEqual(""));
         display.showView(view2);
         manager.setState("test2");
 
-        EasyMock.expect(provider.getViewName("")).andReturn("test1");
+        EasyMock.expect(provider.getViewName("")).andReturn("test1").times(2);
         EasyMock.expect(provider.getView("test1")).andReturn(view1);
         EasyMock.expect(manager.getState()).andReturn("");
         view1.enter(eventParametersEqual(""));
@@ -382,7 +386,7 @@ public class NavigatorTest extends TestCase {
         manager.setState("test1");
 
         EasyMock.expect(provider.getViewName("test1/params"))
-                .andReturn("test1");
+                .andReturn("test1").times(2);
         EasyMock.expect(provider.getView("test1")).andReturn(view1);
         EasyMock.expect(manager.getState()).andReturn("test2");
         view1.enter(eventParametersEqual("params"));
@@ -414,7 +418,8 @@ public class NavigatorTest extends TestCase {
         Navigator navigator = createNavigator(manager, display);
 
         // prepare mocks: what to expect
-        EasyMock.expect(provider.getViewName("test1")).andReturn("test1");
+        EasyMock.expect(provider.getViewName("test1")).andReturn("test1")
+                .times(2);
         EasyMock.expect(provider.getView("test1")).andReturn(view1);
         ViewChangeEvent event1 = new ViewChangeEvent(navigator, null, view1,
                 "test1", "");
@@ -425,7 +430,8 @@ public class NavigatorTest extends TestCase {
         manager.setState("test1");
         listener.addExpectedNavigatorViewChange(event1);
 
-        EasyMock.expect(provider.getViewName("test2")).andReturn("test2");
+        EasyMock.expect(provider.getViewName("test2")).andReturn("test2")
+                .times(2);
         EasyMock.expect(provider.getView("test2")).andReturn(view2);
         ViewChangeEvent event2 = new ViewChangeEvent(navigator, view1, view2,
                 "test2", "");
@@ -493,7 +499,8 @@ public class NavigatorTest extends TestCase {
 
         // prepare mocks: what to expect
         // first listener blocks first view change
-        EasyMock.expect(provider.getViewName("test1")).andReturn("test1");
+        EasyMock.expect(provider.getViewName("test1")).andReturn("test1")
+                .times(2);
         EasyMock.expect(provider.getView("test1")).andReturn(view1);
         EasyMock.expect(manager.getState()).andReturn("");
         ViewChangeEvent event1 = new ViewChangeEvent(navigator, null, view1,
@@ -501,7 +508,8 @@ public class NavigatorTest extends TestCase {
         listener1.addExpectedIsViewChangeAllowed(event1, false);
 
         // second listener blocks second view change
-        EasyMock.expect(provider.getViewName("test1/test")).andReturn("test1");
+        EasyMock.expect(provider.getViewName("test1/test")).andReturn("test1")
+                .times(2);
         EasyMock.expect(provider.getView("test1")).andReturn(view1);
         EasyMock.expect(manager.getState()).andReturn("");
         ViewChangeEvent event2 = new ViewChangeEvent(navigator, null, view1,
@@ -510,7 +518,8 @@ public class NavigatorTest extends TestCase {
         listener2.addExpectedIsViewChangeAllowed(event2, false);
 
         // both listeners allow view change
-        EasyMock.expect(provider.getViewName("test1/bar")).andReturn("test1");
+        EasyMock.expect(provider.getViewName("test1/bar")).andReturn("test1")
+                .times(2);
         EasyMock.expect(provider.getView("test1")).andReturn(view1);
         EasyMock.expect(manager.getState()).andReturn("");
         ViewChangeEvent event3 = new ViewChangeEvent(navigator, null, view1,
@@ -524,7 +533,8 @@ public class NavigatorTest extends TestCase {
         listener2.addExpectedNavigatorViewChange(event3);
 
         // both listeners allow view change from non-null view
-        EasyMock.expect(provider.getViewName("test2")).andReturn("test2");
+        EasyMock.expect(provider.getViewName("test2")).andReturn("test2")
+                .times(2);
         EasyMock.expect(provider.getView("test2")).andReturn(view2);
         EasyMock.expect(manager.getState()).andReturn("view1");
         ViewChangeEvent event4 = new ViewChangeEvent(navigator, view1, view2,
@@ -821,4 +831,63 @@ public class NavigatorTest extends TestCase {
             // Expected
         }
     }
+
+    @Test
+    public void testNavigateTo_navigateSameUriTwice_secondNavigationDoesNothing() {
+        NavigationStateManager manager = new NavigationStateManager() {
+
+            private String state;
+
+            @Override
+            public void setState(String state) {
+                this.state = state;
+            }
+
+            @Override
+            public void setNavigator(Navigator navigator) {
+            }
+
+            @Override
+            public String getState() {
+                return state;
+            }
+        };
+
+        final String viewName = "view";
+
+        final View view = EasyMock.createMock(View.class);
+        ViewProvider provider = new ViewProvider() {
+
+            @Override
+            public String getViewName(String viewAndParameters) {
+                return viewName;
+            }
+
+            @Override
+            public View getView(String viewName) {
+                return view;
+            }
+
+        };
+
+        final int[] count = new int[] { 0 };
+        Navigator navigator = new Navigator(createMockUI(), manager,
+                EasyMock.createMock(ViewDisplay.class)) {
+            @Override
+            protected void navigateTo(View view, String viewName,
+                    String parameters) {
+                count[0] = count[0] + 1;
+                super.navigateTo(view, viewName, parameters);
+            }
+        };
+        navigator.addProvider(provider);
+
+        // First time navigation
+        navigator.navigateTo(viewName);
+        Assert.assertEquals(1, count[0]);
+
+        // Second time navigation to the same view
+        navigator.navigateTo(viewName);
+        Assert.assertEquals(1, count[0]);
+    }
 }