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

122 super text field #134

Merged
merged 5 commits into from
Jun 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions demo-v14/src/main/java/org/vaadin/miki/MainView.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
import org.vaadin.miki.superfields.tabs.SuperTabs;
import org.vaadin.miki.superfields.tabs.TabHandler;
import org.vaadin.miki.superfields.tabs.TabHandlers;
import org.vaadin.miki.superfields.text.CanSelectText;
import org.vaadin.miki.superfields.text.SuperTextArea;
import org.vaadin.miki.superfields.text.SuperTextField;
import org.vaadin.miki.superfields.text.TextSelectionNotifier;
import org.vaadin.miki.superfields.unload.UnloadObserver;

import java.time.LocalDate;
Expand Down Expand Up @@ -132,6 +136,23 @@ private void buildHasValue(Component component, Consumer<Component[]> callback)
((HasValue<?, ?>) component).addValueChangeListener(this::onAnyValueChanged);
}

private void buildCanSelectText(Component component, Consumer<Component[]> callback) {
final Button selectAll = new Button("Select all", event -> ((CanSelectText)component).selectAll());
final Button selectNone = new Button("Select none", event -> ((CanSelectText)component).selectNone());
final HorizontalLayout layout = new HorizontalLayout(new Span("Type something in the field, then click one of the buttons:"), selectAll, selectNone);
layout.setAlignItems(Alignment.CENTER);
callback.accept(new Component[]{
layout
});
if(component instanceof TextSelectionNotifier<?>) {
final Span selection = new Span();
((TextSelectionNotifier<?>) component).addTextSelectionListener(event -> selection.setText(event.getSelectedText()));
callback.accept(new Component[]{
new HorizontalLayout(new Span("You can also select text yourself with keyboard our mouse. Here is the current selection: <"), selection, new Span(">"))
});
}
}

@SuppressWarnings("unchecked")
private void buildItemGrid(Component component, Consumer<Component[]> callback) {
final RadioButtonGroup<Integer> buttons = new RadioButtonGroup<>();
Expand Down Expand Up @@ -258,6 +279,8 @@ public MainView() {
this.components.put(SuperBigDecimalField.class, new SuperBigDecimalField("Big decimal (12 + 3 digits):").withMaximumIntegerDigits(12).withMaximumFractionDigits(3).withMinimumFractionDigits(1).withId("big-decimal"));
this.components.put(SuperDatePicker.class, new SuperDatePicker("Pick a date:").withDatePattern(DatePatterns.YYYY_MM_DD).withValue(LocalDate.now()));
this.components.put(SuperDateTimePicker.class, new SuperDateTimePicker("Pick a date and time:").withDatePattern(DatePatterns.M_D_YYYY_SLASH).withValue(LocalDateTime.now()));
this.components.put(SuperTextField.class, new SuperTextField("Type something:").withPlaceholder("(nothing typed)").withId("super-text-field").withReceivingSelectionEventsFromClient(true));
this.components.put(SuperTextArea.class, new SuperTextArea("Type a lot of something:").withPlaceholder("(nothing typed)").withId("super-text-area").withReceivingSelectionEventsFromClient(true));
this.components.put(SuperTabs.class, new SuperTabs<String>((Supplier<HorizontalLayout>) HorizontalLayout::new)
.withTabContentGenerator(s -> new Paragraph("Did you know? All SuperFields are "+s))
.withItems("Java friendly", "Super-configurable", "Open source")
Expand Down Expand Up @@ -298,6 +321,7 @@ public MainView() {
this.contentBuilders.put(AbstractSuperNumberField.class, this::buildAbstractSuperNumberField);
this.contentBuilders.put(HasLocale.class, this::buildHasLocale);
this.contentBuilders.put(HasValue.class, this::buildHasValue);
this.contentBuilders.put(CanSelectText.class, this::buildCanSelectText);
this.contentBuilders.put(ItemGrid.class, this::buildItemGrid);
this.contentBuilders.put(HasDatePattern.class, this::buildHasDatePattern);
this.contentBuilders.put(SuperTabs.class, this::buildSuperTabs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/
@JsModule("./super-date-picker.js")
@Tag("super-date-picker")
@SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes
public class SuperDatePicker extends DatePicker
implements HasLocale, HasLabel, HasPlaceholder, HasDatePattern,
WithLocaleMixin<SuperDatePicker>, WithLabelMixin<SuperDatePicker>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/
@JsModule("./super-date-time-picker.js")
@Tag("super-date-time-picker")
@SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes
public class SuperDateTimePicker extends DateTimePicker
implements HasLocale, HasLabel, HasDatePattern,
WithLocaleMixin<SuperDateTimePicker>, WithLabelMixin<SuperDateTimePicker>,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.vaadin.miki.superfields.text;

public interface CanReceiveSelectionEventsFromClient {
/**
* Check if client will inform server on selection change.
* Note: this feature is by default turned off.
* @return When {@code true}, each selection change in the client-side component will result in this component broadcasting a {@link TextSelectionEvent}.
*/
boolean isReceivingSelectionEventsFromClient();

/**
* Configures sending events by the client-side component.
* Note: this feature is by default turned off.
* @param receivingSelectionEventsFromClient When {@code false}, selecting text in client-side component will not send an event to server-side component. When {@code true}, it will.
*/
void setReceivingSelectionEventsFromClient(boolean receivingSelectionEventsFromClient);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.vaadin.miki.superfields.text;

import com.vaadin.flow.component.HasElement;

/**
* Marker interface for components that can select text.
* Handles selection using client-side JavaScript.
* @author miki
* @since 2020-05-29
*/
public interface CanSelectText extends HasElement {

void selectAll();

void selectNone();

void select(int from, int to);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package org.vaadin.miki.superfields.text;

import com.vaadin.flow.component.AbstractField;
import com.vaadin.flow.component.ClientCallable;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.textfield.TextArea;
import com.vaadin.flow.shared.Registration;
import org.vaadin.miki.markers.HasLabel;
import org.vaadin.miki.markers.HasPlaceholder;
import org.vaadin.miki.markers.WithIdMixin;
import org.vaadin.miki.markers.WithLabelMixin;
import org.vaadin.miki.markers.WithPlaceholderMixin;
import org.vaadin.miki.markers.WithValueMixin;

/**
* An extension of {@link TextArea} with some useful features.
* @author miki
* @since 2020-06-01
*/
@Tag("super-text-area")
@JsModule("./super-text-area.js")
@SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes
public class SuperTextArea extends TextArea implements CanSelectText, TextSelectionNotifier<SuperTextArea>,
HasLabel, HasPlaceholder, WithIdMixin<SuperTextArea>, WithLabelMixin<SuperTextArea>, WithPlaceholderMixin<SuperTextArea>,
WithReceivingSelectionEventsFromClientMixin<SuperTextArea>,
WithValueMixin<AbstractField.ComponentValueChangeEvent<TextArea, String>, String, SuperTextArea> {

private final TextSelectionDelegate<SuperTextArea> delegate = new TextSelectionDelegate<>(this);

private boolean receivingSelectionEventsFromClient = false;

public SuperTextArea() {
}

public SuperTextArea(String label) {
super(label);
}

public SuperTextArea(String label, String placeholder) {
super(label, placeholder);
}

public SuperTextArea(String label, String initialValue, String placeholder) {
super(label, initialValue, placeholder);
}

public SuperTextArea(ValueChangeListener<? super ComponentValueChangeEvent<TextArea, String>> listener) {
super(listener);
}

public SuperTextArea(String label, ValueChangeListener<? super ComponentValueChangeEvent<TextArea, String>> listener) {
super(label, listener);
}

public SuperTextArea(String label, String initialValue, ValueChangeListener<? super ComponentValueChangeEvent<TextArea, String>> listener) {
super(label, initialValue, listener);
}

@Override
public boolean isReceivingSelectionEventsFromClient() {
return this.receivingSelectionEventsFromClient;
}

@Override
public void setReceivingSelectionEventsFromClient(boolean receivingSelectionEventsFromClient) {
this.receivingSelectionEventsFromClient = receivingSelectionEventsFromClient;
this.delegate.informClientAboutSendingEvents(receivingSelectionEventsFromClient);
}

@Override
public void selectAll() {
this.delegate.selectAll(this::getValue, this::getEventBus);
}

@Override
public void selectNone() {
this.delegate.selectNone(this::getEventBus);
}

@Override
public void select(int from, int to) {
this.delegate.select(this::getValue, this::getEventBus, from, to);
}

@Override
@SuppressWarnings("unchecked")
public Registration addTextSelectionListener(TextSelectionListener<SuperTextArea> listener) {
return this.getEventBus().addListener((Class<TextSelectionEvent<SuperTextArea>>)(Class<?>)TextSelectionEvent.class, listener);
}

@ClientCallable
private void selectionChanged(int start, int end, String selection) {
TextSelectionEvent<SuperTextArea> event = new TextSelectionEvent<>(this, true, start, end, selection);
this.delegate.fireTextSelectionEvent(this.getEventBus(), event);
}

@Override
public void setValue(String value) {
this.delegate.updateAttributeOnValueChange(this::getEventBus);
super.setValue(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package org.vaadin.miki.superfields.text;

import com.vaadin.flow.component.AbstractField;
import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.ClientCallable;
import com.vaadin.flow.component.DetachEvent;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.shared.Registration;
import org.vaadin.miki.markers.HasLabel;
import org.vaadin.miki.markers.HasPlaceholder;
import org.vaadin.miki.markers.WithIdMixin;
import org.vaadin.miki.markers.WithLabelMixin;
import org.vaadin.miki.markers.WithPlaceholderMixin;
import org.vaadin.miki.markers.WithValueMixin;

/**
* An extension of {@link TextField} with some useful (hopefully) features.
* @author miki
* @since 2020-05-29
*/
@Tag("super-text-field")
@JsModule("./super-text-field.js")
@SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes
public class SuperTextField extends TextField implements CanSelectText, TextSelectionNotifier<SuperTextField>,
HasLabel, HasPlaceholder,
WithIdMixin<SuperTextField>, WithLabelMixin<SuperTextField>, WithPlaceholderMixin<SuperTextField>,
WithValueMixin<AbstractField.ComponentValueChangeEvent<TextField, String>, String, SuperTextField>,
WithReceivingSelectionEventsFromClientMixin<SuperTextField> {

private boolean receivingSelectionEventsFromClient = false;

private final TextSelectionDelegate<SuperTextField> delegate = new TextSelectionDelegate<>(this);

public SuperTextField() {
super();
}

public SuperTextField(String label) {
super(label);
}

public SuperTextField(String label, String placeholder) {
super(label, placeholder);
}

public SuperTextField(String label, String initialValue, String placeholder) {
super(label, initialValue, placeholder);
}

public SuperTextField(ValueChangeListener<? super ComponentValueChangeEvent<TextField, String>> listener) {
super(listener);
}

public SuperTextField(String label, ValueChangeListener<? super ComponentValueChangeEvent<TextField, String>> listener) {
super(label, listener);
}

public SuperTextField(String label, String initialValue, ValueChangeListener<? super ComponentValueChangeEvent<TextField, String>> listener) {
super(label, initialValue, listener);
}

@Override
protected void onAttach(AttachEvent attachEvent) {
this.delegate.informClientAboutSendingEvents(this.isReceivingSelectionEventsFromClient());
super.onAttach(attachEvent);
}

@Override
protected void onDetach(DetachEvent detachEvent) {
// detaching means server should not be informed
if(this.isReceivingSelectionEventsFromClient())
this.delegate.informClientAboutSendingEvents(false);
super.onDetach(detachEvent);
}

@Override
@SuppressWarnings("unchecked")
public Registration addTextSelectionListener(TextSelectionListener<SuperTextField> listener) {
return this.getEventBus().addListener((Class<TextSelectionEvent<SuperTextField>>)(Class<?>)TextSelectionEvent.class, listener);
}

@Override
public void selectAll() {
this.delegate.selectAll(this::getValue, this::getEventBus);
}

@Override
public void selectNone() {
this.delegate.selectNone(this::getEventBus);
}

@Override
public void select(int from, int to) {
this.delegate.select(this::getValue, this::getEventBus, from, to);
}

@ClientCallable
private void selectionChanged(int start, int end, String selection) {
TextSelectionEvent<SuperTextField> event = new TextSelectionEvent<>(this, true, start, end, selection);
this.delegate.fireTextSelectionEvent(this.getEventBus(), event);
}

@Override
public boolean isReceivingSelectionEventsFromClient() {
return this.receivingSelectionEventsFromClient;
}

@Override
public void setReceivingSelectionEventsFromClient(boolean receivingSelectionEventsFromClient) {
this.receivingSelectionEventsFromClient = receivingSelectionEventsFromClient;
this.delegate.informClientAboutSendingEvents(receivingSelectionEventsFromClient);
}

@Override
public void setValue(String value) {
this.delegate.updateAttributeOnValueChange(this::getEventBus);
super.setValue(value);
}
}
Loading