From bd5536edb51e67e6941ddd418c0fb2793ea00abf Mon Sep 17 00:00:00 2001 From: =?utf8?q?Leif=20=C3=85strand?= Date: Tue, 16 Dec 2014 15:22:28 +0200 Subject: [PATCH] Add viewport tag generation support (#13710) Change-Id: Ic38f640e44b91b4a1e1e906ab92a751d7a13ee65 --- .../src/com/vaadin/annotations/Viewport.java | 45 ++++++++++++++++ .../annotations/ViewportGeneratorClass.java | 52 ++++++++++++++++++ .../com/vaadin/server/BootstrapHandler.java | 54 +++++++++++++++---- .../com/vaadin/server/ViewportGenerator.java | 36 +++++++++++++ .../tests/components/ui/DynamicViewport.java | 43 +++++++++++++++ .../ui/DynamicViewportEmptyTest.java | 52 ++++++++++++++++++ .../components/ui/DynamicViewportTest.java | 37 +++++++++++++ .../tests/components/ui/InvalidViewport.java | 36 +++++++++++++ .../components/ui/InvalidViewportTest.java | 36 +++++++++++++ .../tests/components/ui/StaticViewport.java | 31 +++++++++++ .../components/ui/StaticViewportTest.java | 37 +++++++++++++ 11 files changed, 450 insertions(+), 9 deletions(-) create mode 100644 server/src/com/vaadin/annotations/Viewport.java create mode 100644 server/src/com/vaadin/annotations/ViewportGeneratorClass.java create mode 100644 server/src/com/vaadin/server/ViewportGenerator.java create mode 100644 uitest/src/com/vaadin/tests/components/ui/DynamicViewport.java create mode 100644 uitest/src/com/vaadin/tests/components/ui/DynamicViewportEmptyTest.java create mode 100644 uitest/src/com/vaadin/tests/components/ui/DynamicViewportTest.java create mode 100644 uitest/src/com/vaadin/tests/components/ui/InvalidViewport.java create mode 100644 uitest/src/com/vaadin/tests/components/ui/InvalidViewportTest.java create mode 100644 uitest/src/com/vaadin/tests/components/ui/StaticViewport.java create mode 100644 uitest/src/com/vaadin/tests/components/ui/StaticViewportTest.java diff --git a/server/src/com/vaadin/annotations/Viewport.java b/server/src/com/vaadin/annotations/Viewport.java new file mode 100644 index 0000000000..67acae8c23 --- /dev/null +++ b/server/src/com/vaadin/annotations/Viewport.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Defines a viewport tag that will be added to the HTML of the host page of a + * UI class. + *

+ * If you want to dynamically provide different viewport values for different + * browser, you should use {@link ViewportGeneratorClass} instead. + * + * @author Vaadin Ltd + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface Viewport { + /** + * Gets the viewport tag content. + * + * @return the viewport tag content + */ + public String value(); +} diff --git a/server/src/com/vaadin/annotations/ViewportGeneratorClass.java b/server/src/com/vaadin/annotations/ViewportGeneratorClass.java new file mode 100644 index 0000000000..7565ad7bae --- /dev/null +++ b/server/src/com/vaadin/annotations/ViewportGeneratorClass.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.vaadin.server.ViewportGenerator; + +/** + * Defines a viewport tag generator class that will be used for generating the + * content of a viewport tag that will be added to the HTML of the host page of + * a UI class. + *

+ * If you want to use the same viewport values for all requests, you can use the + * simpler {@link Viewport} annotation instead. + * + * @see ViewportGenerator + * + * @author Vaadin Ltd + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface ViewportGeneratorClass { + /** + * Gets the viewport generator class to use. Please note that the class must + * be public and have a default constructor. It must additionally be + * declared as static if it's declared as an inner class. + * + * @return the viewport generator class + */ + public Class value(); +} diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java index c34e986fce..985d7ef765 100644 --- a/server/src/com/vaadin/server/BootstrapHandler.java +++ b/server/src/com/vaadin/server/BootstrapHandler.java @@ -37,6 +37,8 @@ import org.jsoup.nodes.Element; import org.jsoup.nodes.Node; import org.jsoup.parser.Tag; +import com.vaadin.annotations.Viewport; +import com.vaadin.annotations.ViewportGeneratorClass; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.Version; import com.vaadin.shared.communication.PushMode; @@ -48,10 +50,10 @@ import elemental.json.JsonObject; import elemental.json.impl.JsonUtil; /** - * + * * @author Vaadin Ltd * @since 7.0.0 - * + * * @deprecated As of 7.0. Will likely change or be removed in a future version */ @Deprecated @@ -287,6 +289,40 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { head.appendElement("meta").attr("http-equiv", "X-UA-Compatible") .attr("content", "IE=11;chrome=1"); + Class uiClass = context.getUIClass(); + + String viewportContent = null; + Viewport viewportAnnotation = uiClass.getAnnotation(Viewport.class); + ViewportGeneratorClass viewportGeneratorClassAnnotation = uiClass + .getAnnotation(ViewportGeneratorClass.class); + if (viewportAnnotation != null + && viewportGeneratorClassAnnotation != null) { + throw new IllegalStateException(uiClass.getCanonicalName() + + " cannot be annotated with both @" + + Viewport.class.getSimpleName() + " and @" + + ViewportGeneratorClass.class.getSimpleName()); + } + + if (viewportAnnotation != null) { + viewportContent = viewportAnnotation.value(); + } else if (viewportGeneratorClassAnnotation != null) { + Class viewportGeneratorClass = viewportGeneratorClassAnnotation + .value(); + try { + viewportContent = viewportGeneratorClass.newInstance() + .getViewport(context.getRequest()); + } catch (Exception e) { + throw new RuntimeException( + "Error processing viewport generator " + + viewportGeneratorClass.getCanonicalName(), e); + } + } + + if (viewportContent != null) { + head.appendElement("meta").attr("name", "viewport") + .attr("content", viewportContent); + } + String title = response.getUIProvider().getPageTitle( new UICreateEvent(context.getRequest(), context.getUIClass())); if (title != null) { @@ -339,9 +375,9 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { * Override this method if you want to add some custom html around around * the div element into which the actual Vaadin application will be * rendered. - * + * * @param context - * + * * @throws IOException */ private void setupMainDiv(BootstrapContext context) throws IOException { @@ -553,13 +589,13 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { /** * Get the URI for the application theme. - * + * * A portal-wide default theme is fetched from the portal shared resource * directory (if any), other themes from the portlet. - * + * * @param context * @param themeName - * + * * @return */ public String getThemeUri(BootstrapContext context, String themeName) { @@ -572,7 +608,7 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { /** * Override if required - * + * * @param context * @return */ @@ -584,7 +620,7 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { /** * Don not override. - * + * * @param context * @return */ diff --git a/server/src/com/vaadin/server/ViewportGenerator.java b/server/src/com/vaadin/server/ViewportGenerator.java new file mode 100644 index 0000000000..b9b5776939 --- /dev/null +++ b/server/src/com/vaadin/server/ViewportGenerator.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.server; + +import java.io.Serializable; + +/** + * Callback for generating a viewport tag content based on a request. + * + * @see ViewportGenerator + * + * @author Vaadin Ltd + */ +public interface ViewportGenerator extends Serializable { + /** + * Generates a viewport tag based on a request. + * + * @param request + * the request for which to generate a viewport tag + * @return the viewport tag content + */ + public String getViewport(VaadinRequest request); +} diff --git a/uitest/src/com/vaadin/tests/components/ui/DynamicViewport.java b/uitest/src/com/vaadin/tests/components/ui/DynamicViewport.java new file mode 100644 index 0000000000..ca9ebcd451 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/DynamicViewport.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.ui; + +import com.vaadin.annotations.ViewportGeneratorClass; +import com.vaadin.server.VaadinRequest; +import com.vaadin.server.ViewportGenerator; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.tests.components.ui.DynamicViewport.MyViewportGenerator; +import com.vaadin.ui.Label; + +@ViewportGeneratorClass(MyViewportGenerator.class) +public class DynamicViewport extends AbstractTestUI { + public static class MyViewportGenerator implements ViewportGenerator { + @Override + public String getViewport(VaadinRequest request) { + String userAgent = request.getHeader("User-Agent"); + System.out.println(userAgent); + if (userAgent == null || userAgent.contains("Chrome")) { + return null; + } + return userAgent; + } + } + + @Override + protected void setup(VaadinRequest request) { + addComponent(new Label("I should have a dynamic viewport tag")); + } +} diff --git a/uitest/src/com/vaadin/tests/components/ui/DynamicViewportEmptyTest.java b/uitest/src/com/vaadin/tests/components/ui/DynamicViewportEmptyTest.java new file mode 100644 index 0000000000..40ec937c1c --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/DynamicViewportEmptyTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.ui; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.DesiredCapabilities; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class DynamicViewportEmptyTest extends MultiBrowserTest { + + @Override + protected Class getUIClass() { + return DynamicViewport.class; + } + + @Override + public List getBrowsersToTest() { + return Arrays.asList(Browser.CHROME.getDesiredCapabilities()); + } + + @Test + public void testGeneratedEmptyViewport() { + openTestURL(); + + List viewportElements = findElements(By + .cssSelector("meta[name=viewport]")); + + Assert.assertTrue("There should be no viewport tags", + viewportElements.isEmpty()); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/ui/DynamicViewportTest.java b/uitest/src/com/vaadin/tests/components/ui/DynamicViewportTest.java new file mode 100644 index 0000000000..f1d9efdbd1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/DynamicViewportTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.ui; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class DynamicViewportTest extends SingleBrowserTest { + + @Test + public void testGeneratedViewport() { + openTestURL(); + + WebElement viewportElement = findElement(By + .cssSelector("meta[name=viewport]")); + + Assert.assertTrue(viewportElement.getAttribute("content").contains( + "PhantomJS")); + } +} diff --git a/uitest/src/com/vaadin/tests/components/ui/InvalidViewport.java b/uitest/src/com/vaadin/tests/components/ui/InvalidViewport.java new file mode 100644 index 0000000000..9557a2d2b0 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/InvalidViewport.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.ui; + +import com.vaadin.annotations.Viewport; +import com.vaadin.annotations.ViewportGeneratorClass; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.tests.components.ui.DynamicViewport.MyViewportGenerator; +import com.vaadin.ui.Label; + +@ViewportGeneratorClass(MyViewportGenerator.class) +@Viewport("myViewport") +public class InvalidViewport extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + addComponent(new Label( + "I shouldn't load because of conflicting viewport definitions")); + + } + +} diff --git a/uitest/src/com/vaadin/tests/components/ui/InvalidViewportTest.java b/uitest/src/com/vaadin/tests/components/ui/InvalidViewportTest.java new file mode 100644 index 0000000000..9d0aac49f7 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/InvalidViewportTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.ui; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class InvalidViewportTest extends SingleBrowserTest { + + @Test + public void testInvalidViewport() { + openTestURL(); + + WebElement heading = findElement(By.tagName("h2")); + + Assert.assertEquals("HTTP ERROR 500", heading.getText()); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/ui/StaticViewport.java b/uitest/src/com/vaadin/tests/components/ui/StaticViewport.java new file mode 100644 index 0000000000..813206dbe8 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/StaticViewport.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.ui; + +import com.vaadin.annotations.Viewport; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Label; + +@Viewport("myViewport") +public class StaticViewport extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + addComponent(new Label("I should have a static viewport tag")); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/ui/StaticViewportTest.java b/uitest/src/com/vaadin/tests/components/ui/StaticViewportTest.java new file mode 100644 index 0000000000..61b3c944c9 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/StaticViewportTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.ui; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class StaticViewportTest extends SingleBrowserTest { + + @Test + public void testStaticViewport() { + openTestURL(); + + WebElement viewportElement = findElement(By + .cssSelector("meta[name=viewport]")); + + Assert.assertEquals("myViewport", + viewportElement.getAttribute("content")); + } +} -- 2.39.5