Skip to content

Commit

Permalink
feat: Add target enums for Anchor (#8346) (#8397)
Browse files Browse the repository at this point in the history
Co-authored-by: Denis Anisimov <[email protected]>
  • Loading branch information
jhult and Denis Anisimov authored May 6, 2021
1 parent 872bbf4 commit d2e211c
Show file tree
Hide file tree
Showing 6 changed files with 335 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.vaadin.flow.component.html;

import java.util.Objects;
import java.util.Optional;

import com.vaadin.flow.component.Component;
Expand All @@ -39,7 +40,8 @@ public class Anchor extends HtmlContainer implements Focusable<Anchor> {
.attributeWithDefault("href", "", false);

private static final PropertyDescriptor<String, Optional<String>> targetDescriptor = PropertyDescriptors
.optionalAttributeWithDefault("target", "");
.optionalAttributeWithDefault("target",
AnchorTarget.DEFAULT.getValue());

private static final String ROUTER_IGNORE_ATTRIBUTE = "router-ignore";

Expand All @@ -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.
Expand Down Expand Up @@ -183,4 +205,47 @@ public Optional<String> getTarget() {
return get(targetDescriptor);
}

/**
* Sets the target window, tab or frame for this anchor. The target may be
* the one of these special values:
* <ul>
* <li><code>AnchorTarget.DEFAULT</code>: Removes the target value. This has
* the same effect as setting the target to <code>AnchorTarget.SELF</code>.
* <li><code>AnchorTarget.SELF</code>: Opens the link in the current
* context.
* <li><code>AnchorTarget.BLANK</code>: Opens the link in a new unnamed
* context.
* <li><code>AnchorTarget.PARENT</code>: Opens the link in the parent
* context, or the current context if there is no parent context.
* <li><code>AnchorTarget.TOP</code>: Opens the link in the top most
* grandparent context, or the current context if there is no parent
* context.
* </ul>
*
* @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<String> target = getTarget();

if (target.isPresent()) {
return AnchorTargetValue.forString(target.get());
}
return AnchorTarget.DEFAULT;
}

}
Original file line number Diff line number Diff line change
@@ -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 <code>target</code> attribute values for an
* <code>&lt;a&gt;</code> element.
*
* @author Vaadin Ltd
* @since
*/
public enum AnchorTarget implements AnchorTargetValue {
/**
* Remove the target value. This has the same effect as <code>SELF</code>.
*/
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 <a>} (anchor) tag.
*/
AnchorTarget(String value) {
this.value = value;
}

/**
* @return value the text value to use by an {@code <a>} (anchor) tag.
*/
@Override
public String getValue() {
return value;
}

}
Original file line number Diff line number Diff line change
@@ -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 <code>target</code> attribute values for an <code>&lt;a&gt;</code>
* 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<AnchorTarget> 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();
}
};
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
Loading

0 comments on commit d2e211c

Please sign in to comment.