diff --git a/flow-html-components/src/main/java/com/vaadin/flow/component/html/Anchor.java b/flow-html-components/src/main/java/com/vaadin/flow/component/html/Anchor.java
index 19f6ae8d168..18cb2b7a785 100644
--- a/flow-html-components/src/main/java/com/vaadin/flow/component/html/Anchor.java
+++ b/flow-html-components/src/main/java/com/vaadin/flow/component/html/Anchor.java
@@ -15,6 +15,7 @@
*/
package com.vaadin.flow.component.html;
+import java.util.Objects;
import java.util.Optional;
import com.vaadin.flow.component.Component;
@@ -39,7 +40,8 @@ public class Anchor extends HtmlContainer implements Focusable {
.attributeWithDefault("href", "", false);
private static final PropertyDescriptor> targetDescriptor = PropertyDescriptors
- .optionalAttributeWithDefault("target", "");
+ .optionalAttributeWithDefault("target",
+ AnchorTarget.DEFAULT.getValue());
private static final String ROUTER_IGNORE_ATTRIBUTE = "router-ignore";
@@ -66,6 +68,26 @@ public Anchor(String href, String text) {
setText(text);
}
+ /**
+ * Creates an anchor component with the given target, text content and href.
+ *
+ * @see #setHref(String)
+ * @see #setText(String)
+ * @see #setTarget(AnchorTargetValue)
+ *
+ * @param href
+ * the href to set
+ * @param text
+ * the text content to set
+ * @param target
+ * the target window, tab or frame
+ */
+ public Anchor(String href, String text, AnchorTarget target) {
+ setHref(href);
+ setText(text);
+ setTarget(target);
+ }
+
/**
* Creates an anchor component with the given text content and stream
* resource.
@@ -183,4 +205,47 @@ public Optional getTarget() {
return get(targetDescriptor);
}
+ /**
+ * Sets the target window, tab or frame for this anchor. The target may be
+ * the one of these special values:
+ *
+ * AnchorTarget.DEFAULT
: Removes the target value. This has
+ * the same effect as setting the target to AnchorTarget.SELF
.
+ * AnchorTarget.SELF
: Opens the link in the current
+ * context.
+ * AnchorTarget.BLANK
: Opens the link in a new unnamed
+ * context.
+ * AnchorTarget.PARENT
: Opens the link in the parent
+ * context, or the current context if there is no parent context.
+ * AnchorTarget.TOP
: Opens the link in the top most
+ * grandparent context, or the current context if there is no parent
+ * context.
+ *
+ *
+ * @param target
+ * the target value, not null
+ */
+ public void setTarget(AnchorTargetValue target) {
+ Objects.requireNonNull(target, "target cannot be null.");
+ setTarget(target.getValue());
+ }
+
+ /**
+ * Gets the target window, tab or frame value for this anchor.
+ *
+ * @see #setTarget(AnchorTargetValue)
+ * @see #getTarget()
+ *
+ * @return the target window value , or {@link AnchorTarget#DEFAULT} if no
+ * target has been set
+ */
+ public AnchorTargetValue getTargetValue() {
+ Optional target = getTarget();
+
+ if (target.isPresent()) {
+ return AnchorTargetValue.forString(target.get());
+ }
+ return AnchorTarget.DEFAULT;
+ }
+
}
diff --git a/flow-html-components/src/main/java/com/vaadin/flow/component/html/AnchorTarget.java b/flow-html-components/src/main/java/com/vaadin/flow/component/html/AnchorTarget.java
new file mode 100644
index 00000000000..a6efab58081
--- /dev/null
+++ b/flow-html-components/src/main/java/com/vaadin/flow/component/html/AnchorTarget.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2000-2020 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.flow.component.html;
+
+/**
+ * Enum representing target
attribute values for an
+ * <a>
element.
+ *
+ * @author Vaadin Ltd
+ * @since
+ */
+public enum AnchorTarget implements AnchorTargetValue {
+ /**
+ * Remove the target value. This has the same effect as SELF
.
+ */
+ DEFAULT(""),
+ /**
+ * Open a link in the current context.
+ */
+ SELF("_self"),
+ /**
+ * Open a link in a new unnamed context.
+ */
+ BLANK("_blank"),
+ /**
+ * Open a link in the parent context, or the current context if there is no
+ * parent context.
+ */
+ PARENT("_parent"),
+ /**
+ * Open a link in the top most grandparent context, or the current context
+ * if there is no parent context.
+ */
+ TOP("_top");
+
+ private final String value;
+
+ /**
+ * @param value
+ * the text value to use by an {@code } (anchor) tag.
+ */
+ AnchorTarget(String value) {
+ this.value = value;
+ }
+
+ /**
+ * @return value the text value to use by an {@code } (anchor) tag.
+ */
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+}
diff --git a/flow-html-components/src/main/java/com/vaadin/flow/component/html/AnchorTargetValue.java b/flow-html-components/src/main/java/com/vaadin/flow/component/html/AnchorTargetValue.java
new file mode 100644
index 00000000000..3d406b1cf5b
--- /dev/null
+++ b/flow-html-components/src/main/java/com/vaadin/flow/component/html/AnchorTargetValue.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2000-2021 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.flow.component.html;
+
+import java.io.Serializable;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+/**
+ * Represents target
attribute values for an <a>
+ * element.
+ *
+ * @author Vaadin Ltd
+ * @since
+ *
+ * @see AnchorTarget
+ *
+ */
+@FunctionalInterface
+public interface AnchorTargetValue extends Serializable {
+
+ /**
+ * Gets the string value representation.
+ *
+ * @return string value representation
+ */
+ String getValue();
+
+ /**
+ * Gets an object instance wrapping the {@code value} string representation.
+ *
+ * @param value
+ * the string value representation, not {@code null}
+ * @return an object wrapping the string value
+ */
+ public static AnchorTargetValue forString(String value) {
+ Optional target = Stream.of(AnchorTarget.values()).filter(
+ type -> type.getValue().equals(Objects.requireNonNull(value)))
+ .findFirst();
+ if (target.isPresent()) {
+ return target.get();
+ }
+ return new AnchorTargetValue() {
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (!obj.getClass().equals(getClass())) {
+ return false;
+ }
+ return value.equals(((AnchorTargetValue) obj).getValue());
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+ };
+ }
+}
diff --git a/flow-html-components/src/test/java/com/vaadin/flow/component/html/AnchorTargetValueTest.java b/flow-html-components/src/test/java/com/vaadin/flow/component/html/AnchorTargetValueTest.java
new file mode 100644
index 00000000000..83ef9b198f0
--- /dev/null
+++ b/flow-html-components/src/test/java/com/vaadin/flow/component/html/AnchorTargetValueTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2000-2021 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.flow.component.html;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class AnchorTargetValueTest {
+
+ @Test
+ public void fromString_notEnum_objectHasValueAndEquals() {
+ AnchorTargetValue value = AnchorTargetValue.forString("foo");
+ Assert.assertEquals("foo", value.getValue());
+
+ AnchorTargetValue value1 = AnchorTargetValue.forString("foo");
+ Assert.assertEquals(value, value1);
+ Assert.assertEquals(value.hashCode(), value1.hashCode());
+ }
+
+ @Test
+ public void fromString_enumValue_resultIsEnum() {
+ AnchorTargetValue value = AnchorTargetValue
+ .forString(AnchorTarget.TOP.getValue());
+ Assert.assertEquals(AnchorTarget.TOP, value);
+ }
+}
diff --git a/flow-html-components/src/test/java/com/vaadin/flow/component/html/AnchorTest.java b/flow-html-components/src/test/java/com/vaadin/flow/component/html/AnchorTest.java
index 3d5b068fb6f..ed04899aa9b 100644
--- a/flow-html-components/src/test/java/com/vaadin/flow/component/html/AnchorTest.java
+++ b/flow-html-components/src/test/java/com/vaadin/flow/component/html/AnchorTest.java
@@ -15,10 +15,13 @@
*/
package com.vaadin.flow.component.html;
-import com.vaadin.flow.component.Text;
+import java.util.Optional;
+
import org.junit.Assert;
import org.junit.Test;
+import com.vaadin.flow.component.Text;
+
public class AnchorTest extends ComponentTest {
@Test
@@ -35,7 +38,27 @@ public void removeHref() {
public void createWithComponent() {
Anchor anchor = new Anchor("#", new Text("Home"));
Assert.assertEquals(anchor.getElement().getAttribute("href"), "#");
+ Assert.assertEquals(anchor.getHref(), "#");
Assert.assertEquals(anchor.getElement().getText(), "Home");
+ Assert.assertEquals(anchor.getText(), "Home");
+ }
+
+ @Test
+ public void createWithTarget() {
+ Anchor anchor = new Anchor("#", "Home");
+ Assert.assertEquals(anchor.getTargetValue(), AnchorTarget.DEFAULT);
+ Assert.assertEquals(anchor.getTarget(), Optional.empty());
+
+ anchor.setTarget(AnchorTarget.BLANK);
+
+ Assert.assertEquals(anchor.getTargetValue(), AnchorTarget.BLANK);
+ Assert.assertEquals(anchor.getTarget(),
+ Optional.of(AnchorTarget.BLANK.getValue()));
+
+ Assert.assertEquals(anchor.getTargetValue(),
+ new Anchor("#", "Home", AnchorTarget.BLANK).getTargetValue());
+ Assert.assertEquals(anchor.getTarget(),
+ new Anchor("#", "Home", AnchorTarget.BLANK).getTarget());
}
@Test
@@ -60,6 +83,44 @@ public void shouldNotBreakBehaviorIfSetHrefWhenHavingRouterIgnoreAttributeBefore
anchor.getElement().getAttribute("router-ignore"));
}
+ @Test
+ public void setTargetValue_useEnum_targetIsSet() {
+ Anchor anchor = new Anchor();
+ anchor.setTarget(AnchorTarget.PARENT);
+
+ Assert.assertEquals(Optional.of(AnchorTarget.PARENT.getValue()),
+ anchor.getTarget());
+ Assert.assertEquals(AnchorTarget.PARENT, anchor.getTargetValue());
+ }
+
+ @Test
+ public void setTargetValue_useObject_targetIsSet() {
+ Anchor anchor = new Anchor();
+ anchor.setTarget(AnchorTargetValue.forString("foo"));
+
+ Assert.assertEquals(Optional.of("foo"), anchor.getTarget());
+ Assert.assertEquals("foo", anchor.getTargetValue().getValue());
+ }
+
+ @Test
+ public void getTargetValue_useEnumStringValue_targetIsReturned() {
+ Anchor anchor = new Anchor();
+ anchor.setTarget(AnchorTarget.SELF.getValue());
+
+ Assert.assertEquals(Optional.of(AnchorTarget.SELF.getValue()),
+ anchor.getTarget());
+ Assert.assertEquals(AnchorTarget.SELF, anchor.getTargetValue());
+ }
+
+ @Test
+ public void getTargetValue_useSomeStringValue_targetIsReturned() {
+ Anchor anchor = new Anchor();
+ anchor.setTarget("foo");
+
+ Assert.assertEquals(Optional.of("foo"), anchor.getTarget());
+ Assert.assertEquals("foo", anchor.getTargetValue().getValue());
+ }
+
// Other test methods in super class
@Override
diff --git a/flow-html-components/src/test/java/com/vaadin/flow/component/html/HtmlComponentSmokeTest.java b/flow-html-components/src/test/java/com/vaadin/flow/component/html/HtmlComponentSmokeTest.java
index 85c03d799ac..ac361d940c1 100644
--- a/flow-html-components/src/test/java/com/vaadin/flow/component/html/HtmlComponentSmokeTest.java
+++ b/flow-html-components/src/test/java/com/vaadin/flow/component/html/HtmlComponentSmokeTest.java
@@ -26,7 +26,14 @@
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
import java.util.function.Supplier;
import org.junit.Assert;
@@ -197,6 +204,15 @@ private static boolean isSpecialSetter(Method method) {
&& method.getParameterTypes()[0] == Component.class) {
return true;
}
+
+ // Anchor.setTarget(AnchorTargetValue) -
+ // https://github.com/vaadin/flow/issues/8346
+ if (method.getDeclaringClass() == Anchor.class
+ && method.getName().equals("setTarget")
+ && method.getParameterTypes()[0] == AnchorTargetValue.class) {
+ return true;
+ }
+
// setFoo(AbstractStreamResource) for resource URLs
if (method.getParameterCount() == 1 && AbstractStreamResource.class
.isAssignableFrom(method.getParameters()[0].getType())) {