Skip to content

Commit 32c4914

Browse files
authored
feat: DisabledUpdateMode for ShortcutRegistration (#20874)
* feat: DisabledUpdateMode for ShortcutRegistration
1 parent 248bbd3 commit 32c4914

File tree

4 files changed

+85
-4
lines changed

4 files changed

+85
-4
lines changed

flow-server/src/main/java/com/vaadin/flow/component/ShortcutRegistration.java

+39-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.stream.Collectors;
3131

3232
import com.vaadin.flow.component.internal.UIInternals;
33+
import com.vaadin.flow.dom.DisabledUpdateMode;
3334
import com.vaadin.flow.dom.DomListenerRegistration;
3435
import com.vaadin.flow.function.SerializableConsumer;
3536
import com.vaadin.flow.function.SerializableSupplier;
@@ -95,6 +96,8 @@ public class ShortcutRegistration implements Registration, Serializable {
9596

9697
private List<Registration> registrations = new ArrayList<>();
9798

99+
private DisabledUpdateMode mode = DisabledUpdateMode.ONLY_WHEN_ENABLED;
100+
98101
// beforeClientResponse callback
99102
// needs to be an anonymous class to prevent deserialization issues
100103
// see #17201
@@ -517,6 +520,39 @@ public Component getLifecycleOwner() {
517520
return lifecycleOwner;
518521
}
519522

523+
/**
524+
* Configure whether this listener will be called even in cases when the
525+
* component is disabled. Defaults to
526+
* {@link DisabledUpdateMode#ONLY_WHEN_ENABLED}.
527+
*
528+
* @param disabledUpdateMode
529+
* {@link DisabledUpdateMode#ONLY_WHEN_ENABLED} to only fire
530+
* events when the component is enabled,
531+
* {@link DisabledUpdateMode#ALWAYS} to fire events also when the
532+
* component is disabled.
533+
*
534+
* @return this registration, for chaining
535+
*/
536+
public ShortcutRegistration setDisabledUpdateMode(
537+
DisabledUpdateMode disabledUpdateMode) {
538+
if (disabledUpdateMode == null) {
539+
throw new IllegalArgumentException(
540+
"RPC communication control mode for disabled element must not be null");
541+
}
542+
mode = disabledUpdateMode;
543+
return this;
544+
}
545+
546+
/**
547+
* Returns whether this listener will be called even in cases when the
548+
* component is disabled.
549+
*
550+
* @return current disabledUpdateMode for this listener
551+
*/
552+
public DisabledUpdateMode getDisabledUpdateMode() {
553+
return mode;
554+
}
555+
520556
/**
521557
* Used for testing purposes.
522558
*
@@ -637,8 +673,9 @@ private Component getComponentEventSource(int listenOnIndex) {
637673
}
638674

639675
private void fireShortcutEvent(Component component) {
640-
if (ancestorsOrSelfAreVisible(lifecycleOwner)
641-
&& lifecycleOwner.getElement().isEnabled()) {
676+
if (ancestorsOrSelfAreVisible(lifecycleOwner) && (lifecycleOwner
677+
.getElement().isEnabled()
678+
|| DisabledUpdateMode.ALWAYS.equals(getDisabledUpdateMode()))) {
642679
invokeShortcutEventListener(component);
643680
}
644681
}

flow-server/src/test/java/com/vaadin/flow/component/ShortcutRegistrationTest.java

+19
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
import com.vaadin.flow.component.internal.PendingJavaScriptInvocation;
3535
import com.vaadin.flow.component.internal.UIInternals;
36+
import com.vaadin.flow.dom.DisabledUpdateMode;
3637
import com.vaadin.flow.dom.Element;
3738
import com.vaadin.flow.dom.ElementFactory;
3839
import com.vaadin.flow.function.SerializableConsumer;
@@ -506,6 +507,24 @@ public void constructedRegistration_lifecycleOnwerIsDisabled_shorcutEventIsNotFi
506507
Assert.assertNull(event.get());
507508
}
508509

510+
@Test
511+
public void constructedRegistration_lifecycleOwnerIsDisabledWithDisabledUpdateModeAlways_shortcutEventIsFired() {
512+
AtomicReference<ShortcutEvent> event = new AtomicReference<>();
513+
514+
new ShortcutRegistration(lifecycleOwner, () -> listenOn, event::set,
515+
Key.KEY_A).setDisabledUpdateMode(DisabledUpdateMode.ALWAYS);
516+
517+
Element element = mockLifecycle(true);
518+
element.setEnabled(false);
519+
520+
clientResponse();
521+
522+
listenOn[0].getEventBus()
523+
.fireEvent(new KeyDownEvent(listenOn[0], Key.KEY_A.toString()));
524+
525+
Assert.assertNotNull(event.get());
526+
}
527+
509528
@Test
510529
public void constructedRegistration_lifecycleOnwerIsInvisible_shorcutEventIsNotFired() {
511530
AtomicReference<ShortcutEvent> event = new AtomicReference<>();

flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/ShortcutsView.java

+15
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.vaadin.flow.component.html.NativeButton;
3030
import com.vaadin.flow.component.html.Paragraph;
3131
import com.vaadin.flow.data.value.ValueChangeMode;
32+
import com.vaadin.flow.dom.DisabledUpdateMode;
3233
import com.vaadin.flow.router.Route;
3334
import com.vaadin.flow.uitest.servlet.ViewTestLayout;
3435

@@ -86,6 +87,20 @@ public ShortcutsView() {
8687

8788
add(disabledButton);
8889

90+
// DisabledUpdateMode.ALWAYS makes shortcut work when component is
91+
// disabled
92+
NativeButton disabledButtonWithAlwaysMode = new NativeButton();
93+
disabledButtonWithAlwaysMode.setEnabled(false);
94+
disabledButtonWithAlwaysMode.addClickListener(event -> {
95+
actual.setValue("DISABLED CLICKED");
96+
});
97+
disabledButtonWithAlwaysMode
98+
.addClickShortcut(Key.KEY_P, KeyModifier.SHIFT,
99+
KeyModifier.CONTROL)
100+
.setDisabledUpdateMode(DisabledUpdateMode.ALWAYS);
101+
102+
add(disabledButtonWithAlwaysMode);
103+
89104
// listenOnScopesTheShortcut
90105
Div subview = new Div();
91106
subview.setId("subview");

flow-tests/test-root-context/src/test/java/com/vaadin/flow/uitest/ui/ShortcutsIT.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public void shortcutsOnlyWorkWhenComponentIsVisible() {
8080

8181
@Test
8282
public void shortcutOnlyWorksWhenComponentIsEnabled() {
83-
sendKeys(Keys.CONTROL, "U"); // ctrl+shift+u
83+
sendKeys(Keys.CONTROL, Keys.SHIFT, "u");
8484

8585
// clicking the button disables it, and clicking again should not have
8686
// and effect
@@ -89,7 +89,17 @@ public void shortcutOnlyWorksWhenComponentIsEnabled() {
8989
resetActual();
9090
assertActualEquals(DEFAULT_VALUE);
9191

92-
sendKeys(Keys.CONTROL, "U"); // ctrl+shift+u
92+
sendKeys(Keys.CONTROL, Keys.SHIFT, "u");
93+
assertActualEquals(DEFAULT_VALUE);
94+
}
95+
96+
@Test
97+
public void shortcutWithDisabledUpdateModeAlwaysWorksWhenComponentIsDisabled() {
98+
sendKeys(Keys.CONTROL, Keys.SHIFT, "p");
99+
100+
assertActualEquals("DISABLED CLICKED");
101+
102+
resetActual();
93103
assertActualEquals(DEFAULT_VALUE);
94104
}
95105

0 commit comments

Comments
 (0)