Skip to content

Commit

Permalink
feat: add logic for Popover auto-adding on setting target (#6565)
Browse files Browse the repository at this point in the history
  • Loading branch information
web-padawan authored Aug 27, 2024
1 parent f0062f8 commit 7000581
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public class Popover extends Component implements HasAriaLabel, HasComponents,

private Component target;
private Registration targetAttachRegistration;
private Registration targetDetachRegistration;
private boolean autoAddedToTheUi;

private boolean openOnClick = true;
private boolean openOnHover = false;
Expand Down Expand Up @@ -664,6 +666,9 @@ private void updateTrigger() {
* <p>
* By default, the popover can be opened with a click on the target
* component.
* <p>
* Note: setting target will also add the popover to the {@code <body>} if
* it's not yet attached anywhere.
*
* @param target
* the target component for this popover, can be {@code null} to
Expand All @@ -679,6 +684,12 @@ public void setTarget(Component target) {

if (this.target != null) {
targetAttachRegistration.remove();
targetDetachRegistration.remove();
}

if (autoAddedToTheUi) {
getElement().removeFromParent();
autoAddedToTheUi = false;
}

this.target = target;
Expand All @@ -693,10 +704,22 @@ public void setTarget(Component target) {
target.getUI().ifPresent(this::onTargetAttach);
targetAttachRegistration = target
.addAttachListener(e -> onTargetAttach(e.getUI()));
targetDetachRegistration = target.addDetachListener(e -> {
if (autoAddedToTheUi) {
getElement().removeFromParent();
autoAddedToTheUi = false;
}
});
}

private void onTargetAttach(UI ui) {
if (target != null) {
ui.beforeClientResponse(ui, context -> {
if (getElement().getNode().getParent() == null) {
ui.addToModalComponent(this);
autoAddedToTheUi = true;
}
});
getElement().executeJs("this.target = $0", target.getElement());
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright 2000-2024 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.popover;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;

import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.server.VaadinSession;

/**
* @author Vaadin Ltd.
*/
public class PopoverAutoAddTest {
private UI ui = new UI();

@Before
public void setup() {
UI.setCurrent(ui);

VaadinSession session = Mockito.mock(VaadinSession.class);
Mockito.when(session.hasLock()).thenReturn(true);
ui.getInternals().setSession(session);
}

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

@Test
public void setTarget_autoAdded() {
Popover popover = new Popover();
Div target = new Div();
popover.setTarget(target);
ui.add(target);

fakeClientResponse();
Assert.assertEquals(ui.getElement(), popover.getElement().getParent());
}

@Test
public void setTarget_clearTarget_autoRemoved() {
Popover popover = new Popover();
Div target = new Div();
popover.setTarget(target);
ui.add(target);
fakeClientResponse();

popover.setTarget(null);

fakeClientResponse();
Assert.assertNull(popover.getElement().getParent());
}

@Test
public void setTarget_detachTarget_autoRemoved() {
Popover popover = new Popover();
Div target = new Div();
popover.setTarget(target);
ui.add(target);
fakeClientResponse();

ui.remove(target);

fakeClientResponse();
Assert.assertNull(popover.getElement().getParent());
}

@Test
public void setTarget_changeTarget_notAutoRemoved() {
Popover popover = new Popover();
Div target = new Div();
popover.setTarget(target);
ui.add(target);
fakeClientResponse();

Div other = new Div();
ui.add(other);
popover.setTarget(other);
fakeClientResponse();

Assert.assertEquals(ui.getElement(), popover.getElement().getParent());
}

@Test
public void setTarget_changeTarget_detachOldTarget_notAutoRemoved() {
Popover popover = new Popover();
Div target = new Div();
popover.setTarget(target);
ui.add(target);
fakeClientResponse();

Div other = new Div();
ui.add(other);
popover.setTarget(other);
fakeClientResponse();

ui.remove(target);
fakeClientResponse();
Assert.assertEquals(ui.getElement(), popover.getElement().getParent());
}

@Test
public void setTarget_changeToDetachedTarget_autoRemoved() {
Popover popover = new Popover();
Div target = new Div();
popover.setTarget(target);
ui.add(target);
fakeClientResponse();

Div other = new Div();
popover.setTarget(other);
fakeClientResponse();

Assert.assertNull(popover.getElement().getParent());
}

private void fakeClientResponse() {
ui.getInternals().getStateTree().runExecutionsBeforeClientResponse();
ui.getInternals().getStateTree().collectChanges(ignore -> {
});
}
}

0 comments on commit 7000581

Please sign in to comment.