Skip to content

Commit

Permalink
fix: Proper handling of href when the anchor is disabled/enabled (#12616
Browse files Browse the repository at this point in the history
) (#12631)

fixes #10924

Co-authored-by: Matti Tahvonen <matti@vaadin.com>
  • Loading branch information
vaadin-bot and mstahv committed Dec 24, 2021
1 parent 80d104c commit bc025ca
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 2 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.io.Serializable;
import java.util.Objects;
import java.util.Optional;

Expand All @@ -27,6 +28,7 @@
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.server.AbstractStreamResource;
import com.vaadin.flow.server.StreamResource;
import com.vaadin.flow.server.StreamResourceRegistry;

/**
* Component representing an <code>&lt;a&gt;</code> element.
Expand All @@ -46,6 +48,7 @@ public class Anchor extends HtmlContainer
AnchorTarget.DEFAULT.getValue());

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

/**
* Creates a new empty anchor component.
Expand Down Expand Up @@ -127,6 +130,9 @@ public Anchor(String href, Component... components) {
/**
* Sets the URL that this anchor links to.
* <p>
* A disabled Anchor removes the attribute from the HTML element, but it is
* stored (and reused when enabled again) in the server-side component.
* <p>
* Use the method {@link #removeHref()} to remove the <b>href</b> attribute
* instead of setting it to an empty string.
*
Expand All @@ -137,7 +143,11 @@ public Anchor(String href, Component... components) {
* the href to set
*/
public void setHref(String href) {
set(hrefDescriptor, href);
if (href == null) {
throw new IllegalArgumentException("Href must not be null");
}
this.href = href;
assignHrefAttribute();
}

/**
Expand All @@ -148,6 +158,7 @@ public void setHref(String href) {
*/
public void removeHref() {
getElement().removeAttribute("href");
href = null;
}

/**
Expand All @@ -158,8 +169,9 @@ public void removeHref() {
* the resource value, not null
*/
public void setHref(AbstractStreamResource href) {
getElement().setAttribute("href", href);
this.href = href;
getElement().setAttribute(ROUTER_IGNORE_ATTRIBUTE, true);
assignHrefAttribute();
}

/**
Expand All @@ -170,9 +182,37 @@ public void setHref(AbstractStreamResource href) {
* @return the href value, or <code>""</code> if no href has been set
*/
public String getHref() {
if (href instanceof String) {
// let the method return the actual href string even if disabled
return (String) href;
} else if (href instanceof AbstractStreamResource) {
return StreamResourceRegistry.getURI((AbstractStreamResource) href)
.toString();
}
return get(hrefDescriptor);
}

@Override
public void onEnabledStateChanged(boolean enabled) {
super.onEnabledStateChanged(enabled);
assignHrefAttribute();
}

private void assignHrefAttribute() {
if (isEnabled()) {
if (href != null) {
if (href instanceof AbstractStreamResource) {
getElement().setAttribute("href",
(AbstractStreamResource) href);
} else {
set(hrefDescriptor, (String) href);
}
}
} else {
getElement().removeAttribute("href");
}
}

/**
* Sets the target window, tab or frame for this anchor. The target is
* either the <code>window.name</code> of a specific target, or one of these
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,24 @@

import java.util.Optional;

import com.vaadin.flow.component.UI;
import com.vaadin.flow.server.AbstractStreamResource;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;

import com.vaadin.flow.component.Text;

public class AnchorTest extends ComponentTest {

private UI ui;

@After
public void tearDown() {
ui = null;
UI.setCurrent(null);
}

@Test
public void removeHref() {
Anchor anchor = new Anchor();
Expand Down Expand Up @@ -134,4 +145,131 @@ protected void addProperties() {
public void testHasAriaLabelIsImplemented() {
super.testHasAriaLabelIsImplemented();
}

@Test
public void setEnabled_anchorWithoutHref_doesNotThrow() {
Anchor anchor = new Anchor();
anchor.setEnabled(false);

anchor.setEnabled(true);
Assert.assertTrue(anchor.isEnabled());

anchor.setHref("foo");
anchor.setEnabled(false);
anchor.removeHref();
anchor.setEnabled(true);
}

@Test
public void disabledAnchor_removeHref_hrefIsEmpty() {
Anchor anchor = new Anchor();
anchor.setHref("foo");
anchor.setEnabled(false);
Assert.assertEquals("foo", anchor.getHref());
anchor.setHref("bar");
Assert.assertEquals("bar", anchor.getHref());
anchor.removeHref();
Assert.assertEquals("", anchor.getHref());
anchor.setEnabled(true);
Assert.assertEquals("", anchor.getHref());
}

@Test
public void disabledAnchor_hrefIsRemoved_enableAnchor_hrefIsRestored() {
Anchor anchor = new Anchor("foo", "bar");
anchor.setEnabled(false);

Assert.assertFalse(anchor.getElement().hasAttribute("href"));

anchor.setEnabled(true);
Assert.assertTrue(anchor.getElement().hasAttribute("href"));
Assert.assertEquals("foo", anchor.getHref());
}

@Test
public void disabledAnchor_setHrefWhenDisabled_enableAnchor_hrefIsPreserved() {
Anchor anchor = new Anchor("foo", "bar");
anchor.setEnabled(false);

anchor.setHref("baz");

anchor.setEnabled(true);

Assert.assertTrue(anchor.getElement().hasAttribute("href"));
Assert.assertEquals("baz", anchor.getHref());
}

@Test
public void disabledAnchor_setResourceWhenDisabled_enableAnchor_resourceIsPreserved() {
Anchor anchor = new Anchor("foo", "bar");
anchor.setEnabled(false);

mockUI();
anchor.setHref(new AbstractStreamResource() {

@Override
public String getName() {
return "baz";
}
});
anchor.setEnabled(true);

Assert.assertTrue(anchor.getElement().hasAttribute("href"));
}

@Test
public void disabledAnchor_setResource_hrefIsRemoved_enableAnchor_hrefIsRestored() {
mockUI();
AbstractStreamResource resource = new AbstractStreamResource() {

@Override
public String getName() {
return "foo";
}

};
Anchor anchor = new Anchor(resource, "bar");
String href = anchor.getHref();
anchor.setEnabled(false);

Assert.assertFalse(anchor.getElement().hasAttribute("href"));
Assert.assertEquals(href, anchor.getHref());

anchor.setEnabled(true);
Assert.assertEquals(href, anchor.getHref());
}

@Test
public void disabledAnchor_setResourceWhenDisabled_hrefIsPreserved() {
mockUI();
AbstractStreamResource resource = new AbstractStreamResource() {

@Override
public String getName() {
return "foo";
}

};
Anchor anchor = new Anchor(resource, "bar");
String href = anchor.getHref();
anchor.setEnabled(false);

anchor.setHref(new AbstractStreamResource() {

@Override
public String getName() {
return "baz";
}
});

anchor.setEnabled(true);

Assert.assertTrue(anchor.getElement().hasAttribute("href"));
Assert.assertNotEquals(href, anchor.getHref());
}

private void mockUI() {
ui = new UI();
UI.setCurrent(ui);
}
}

0 comments on commit bc025ca

Please sign in to comment.