Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues/4893 Finalize shortcut api #4969

Merged
merged 18 commits into from
Jan 18, 2019

Conversation

ujoni
Copy link
Contributor

@ujoni ujoni commented Jan 18, 2019

Adds support for Keyboard Shortcuts to Flow.

Shortcut entry points:

  • UI for global shortcuts
  • Focusable for focus shortcuts
  • ClickNotifier for click shortcuts
  • Shortcuts for registering a more customizable shortcut

There are two method variants for adding shortcuts: Registration add...(...) and ShortcutRegistration register...(...). add-methods perform the most basic of registrations and minimal configurability while register-methods return ShortcutRegistration which provides a fluent configuration API for the shortcut.

ShortcutRegistration provides methods for fluently configuring Keys, KeyModifiers, lifecycleOwner, and client-side event behavior (preventDefault, stopPropagation). The shortcuts recognize two semantics for Components: owner and lifecycleOwner.

Owner is the component to which the shortcut's event listener is tied to. In most cases, this will be an instance of UI, making the shortcut operate in the global scope. If another component is assigned as the owner, the shortcut will only be triggered, if some child html element of the component is focused during the key event.

LifecycleOwner is a component which controls, when the shortcut is active. If the lifecycleOwner is detached or invisible, the shortcut won't get triggered (in case of the invisibility, the check is on the server-side, so the shortcut will in fact get triggered but not executed).


This change is Reviewable

Joni Uitto added 17 commits January 18, 2019 10:32
ShortcutRegistration is a result of adding a shortcut and can be used
to both configure and remove a shortcut.

ShortcutActions is used to register custom shortcut actions.
ClickNotifier has a method for adding a "click shortcut" and Focusable
has a method for adding a "focus shortcut".
Still lacking few features:
- visibility check for components
- Key designator which follows platform conventions (or an API for
  making shortcuts conform to platform conventions)
Added comments to ShortcutRegistration constructor
Covers:
- click shortcut
- focus shortcut
- scoped shortcut
- global shortcut
- shortcut tied to visibility flopping component
- shortcut tied to attach/detach flopping component
And renamed a method to better represent its functionality.
The method is an overload of the Registration addShortcut(...) variant and it
allows for configuration of both owner and lifecycle owner.

Also, in Shortcuts, where there was Component owner before, now is Component
lifecycleOwner - when writing the IT tests, I noticed a distinct need to make
configuring the lifecycle owner easier. I didn't care about owner over much.
Copy link
Contributor

@bogdanudrescu bogdanudrescu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewed 10 of 10 files at r1.
Reviewable status: :shipit: complete! all discussions resolved, 1 of 1 LGTMs obtained

Copy link
Contributor

@bogdanudrescu bogdanudrescu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewed 1 of 1 files at r2.
Reviewable status: :shipit: complete! all discussions resolved, 1 of 1 LGTMs obtained

KeyModifier... keyModifiers) {
if (lifecycleOwner == null) {
throw new InvalidParameterException(String.format(NULL,
"lifecycleOwner"));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Define a constant instead of duplicating this literal "lifecycleOwner" 3 times. rule

* @author Vaadin Ltd.
* @since
*/
public final class Shortcuts {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Add a private constructor to hide the implicit public one. rule

"lifecycleOwner"));
}
if (command == null) {
throw new InvalidParameterException(String.format(NULL, "command"));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Define a constant instead of duplicating this literal "command" 4 times. rule

}

if (key == null) {
throw new InvalidParameterException(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

INFO Load of known null value in com.vaadin.flow.component.Focusable.registerFocusShortcut(Key) rule

}

if (key == null) {
throw new InvalidParameterException(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

INFO Load of known null value in com.vaadin.flow.component.Focusable.addFocusShortcut(Key, KeyModifier[]) rule

}

if (key == null) {
throw new InvalidParameterException(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

INFO Load of known null value in com.vaadin.flow.component.ClickNotifier.addClickShortcut(Key, KeyModifier[]) rule

String.format(Shortcuts.NULL, key));
}

final Component _this = (Component) this;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Rename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'. rule

}

if (key == null) {
throw new InvalidParameterException(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

INFO Load of known null value in com.vaadin.flow.component.ClickNotifier.registerClickShortcut(Key) rule

executionRegistration.remove();
}
// isLifecycleOwnerAttached checks for UI status
executionRegistration = lifecycleOwner.getUI().get()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Call "Optional#isPresent()" before accessing the value. rule

* together.
*/
private static class CompoundRegistration implements Registration {
Set<Registration> registrations;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR Make "registrations" private or transient. rule


private static String generateEventKeyFilter(Key key) {
// will now allow shortcut to happen without primary key
if (key == null) return "false";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR At most one statement is allowed per line, but 2 statements were found on this line. rule


private void markClean() {
synchronized (this) {
if (!isDirty.get()) return;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR At most one statement is allowed per line, but 2 statements were found on this line. rule

keydownRegistration);
}
}
else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Move this "else" on the same line that the previous closing curly brace. rule

private static String generateEventModifierFilter(
Collection<Key> modifiers) {

if (modifiers.size() == 0) return "true";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR At most one statement is allowed per line, but 2 statements were found on this line. rule
MINOR Use isEmpty() to check whether the collection is empty or not. rule

assert lifecycleOwner != null;

synchronized (this) {
if (isDirty.get()) return;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR At most one statement is allowed per line, but 2 statements were found on this line. rule

return this;
}

/**
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL First sentence of Javadoc is incomplete (period is missing) or not present. rule

}

private final SerializableConsumer<ExecutionContext>
beforeClientResponseConsumer = executionContext -> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Move this variable to comply with Java Code Conventions. rule

prepareForClientResponse();
}
}
else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Move this "else" on the same line that the previous closing curly brace. rule

Copy link
Contributor

@bogdanudrescu bogdanudrescu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewable status: 18 unresolved discussions, 1 of 1 LGTMs obtained (waiting on @vaadin-bot)

Copy link
Contributor

@bogdanudrescu bogdanudrescu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dismissed @vaadin-bot from 18 discussions.
Reviewable status: :shipit: complete! all discussions resolved, 1 of 1 LGTMs obtained

@bogdanudrescu bogdanudrescu merged commit c476c0e into master Jan 18, 2019
@bogdanudrescu bogdanudrescu added this to the 1.3.0.alpha3 milestone Jan 18, 2019
@ujoni ujoni deleted the issues/4893_finalize_shortcut_api branch January 29, 2019 11:49
caalador pushed a commit that referenced this pull request Jan 30, 2019
* Adds isModifier(Key) to Key interface

* Brings over DX tested ShortcutRegistration and ShortcutActions

ShortcutRegistration is a result of adding a shortcut and can be used
to both configure and remove a shortcut.

ShortcutActions is used to register custom shortcut actions.

* Adds shortcut support to ClickNotifier and Focusable interfaces

ClickNotifier has a method for adding a "click shortcut" and Focusable
has a method for adding a "focus shortcut".

* Newest API changes for Shortcuts based on the DX testing.

Still lacking few features:
- visibility check for components
- Key designator which follows platform conventions (or an API for
  making shortcuts conform to platform conventions)

* Shortcuts UI test basefile (old demo file)

* Added AltGr to KeyModifiers for completeness (also, Key.ALT != Key.ALT_GRAPH)

* Removed char-based APIs from Shortcuts.

Added comments to ShortcutRegistration constructor

* Small unit tests for shortcut registration and due fixes.

* Visibility handling, cleaning, and more unit tests

* Updated JavaDocs for ShortcutRegistration

* Basic IT tests for Shortcuts

Covers:
- click shortcut
- focus shortcut
- scoped shortcut
- global shortcut
- shortcut tied to visibility flopping component
- shortcut tied to attach/detach flopping component

* Cleaned some duplicate code from ShortcutRegistration.
And renamed a method to better represent its functionality.

* Added JavaDocs to Shortcuts.java and an extra method.
The method is an overload of the Registration addShortcut(...) variant and it
allows for configuration of both owner and lifecycle owner.

Also, in Shortcuts, where there was Component owner before, now is Component
lifecycleOwner - when writing the IT tests, I noticed a distinct need to make
configuring the lifecycle owner easier. I didn't care about owner over much.

* Added JavaDocs to UI's shortcut methods

* Added JavaDocs for Focusable's shortcut methods

* JavaDoc for ClickNotifier's shortcut methods

* Fixed IT test since the Shortcuts API had changed a little

* Added Shortcuts.java exclusion pattern for serialization test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants