import static com.vaadin.shared.EventId.BLUR;
import static com.vaadin.shared.EventId.FOCUS;
+import java.util.function.Supplier;
+
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.DomEvent.Type;
ComponentConnector connector, H handler, String eventIdentifier,
HandlerRegistration handlerRegistration, Type<H> type,
Widget widget) {
+ return updateHandler(connector, eventIdentifier, handlerRegistration,
+ () -> widget.addDomHandler(handler, type));
+ }
+
+ /**
+ * Updates handler registered using {@code handlerProvider}: removes it if
+ * connector doesn't have anymore {@code eventIdentifier} using provided
+ * {@code handlerRegistration} and adds it via provided
+ * {@code handlerProvider} if connector has event listener with
+ * {@code eventIdentifier}.
+ *
+ * @param connector
+ * connector to check event listener presence
+ * @param eventIdentifier
+ * event identifier whose presence in the connector is checked
+ * @param handlerRegistration
+ * resulting handler registration to remove added handler in case
+ * of absence event listener
+ * @param handlerProvider
+ * the strategy to register handler
+ * @return handlerRegistration which should be used to remove registered
+ * handler via {@code handlerProvider}
+ */
+ public static <H extends EventHandler, W extends Widget> HandlerRegistration updateHandler(
+ ComponentConnector connector, String eventIdentifier,
+ HandlerRegistration handlerRegistration,
+ Supplier<HandlerRegistration> handlerProvider) {
if (connector.hasEventListener(eventIdentifier)) {
if (handlerRegistration == null) {
- handlerRegistration = widget.addDomHandler(handler, type);
+ handlerRegistration = handlerProvider.get();
}
} else if (handlerRegistration != null) {
handlerRegistration.removeHandler();
}
return handlerRegistration;
}
+
}
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.HasAllFocusHandlers;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.EventHelper;
private final Widget widget;
private HandlerRegistration focusRegistration = null;
private HandlerRegistration blurRegistration = null;
+ private HandlerRegistration stateChangeRegistration = null;
- public static void addHandlers(AbstractComponentConnector connector) {
- addHandlers(connector, connector.getWidget());
+ /**
+ * Add focus/blur handlers to the widget of the {@code connector}.
+ *
+ * @param connector
+ * connector whose widget is a target to add focus/blur handlers
+ * @return ConnectorFocusAndBlurHandler instance to remove all registered
+ * handlers
+ */
+ public static ConnectorFocusAndBlurHandler addHandlers(
+ AbstractComponentConnector connector) {
+ return addHandlers(connector, connector.getWidget());
}
- public static void addHandlers(AbstractComponentConnector connector,
- Widget widget) {
- connector.addStateChangeHandler("registeredEventListeners",
- new ConnectorFocusAndBlurHandler(connector, widget));
+ /**
+ * Add focus/blur handlers to the widget and a state change handler for the
+ * {@code connector}.
+ *
+ * @param connector
+ * connector to register state change handler
+ * @param widget
+ * widget to register focus/blur handler
+ * @return ConnectorFocusAndBlurHandler instance to remove all registered
+ * handlers
+ */
+ public static ConnectorFocusAndBlurHandler addHandlers(
+ AbstractComponentConnector connector, Widget widget) {
+ ConnectorFocusAndBlurHandler handler = new ConnectorFocusAndBlurHandler(
+ connector, widget);
+ handler.stateChangeRegistration = connector
+ .addStateChangeHandler("registeredEventListeners", handler);
+ return handler;
}
private ConnectorFocusAndBlurHandler(AbstractComponentConnector connector,
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
- focusRegistration = EventHelper.updateHandler(connector, this,
- EventId.FOCUS, focusRegistration, FocusEvent.getType(), widget);
- blurRegistration = EventHelper.updateHandler(connector, this,
- EventId.BLUR, blurRegistration, BlurEvent.getType(), widget);
+ if (widget instanceof HasAllFocusHandlers) {
+ HasAllFocusHandlers focusHandlers = (HasAllFocusHandlers) widget;
+ focusRegistration = EventHelper.updateHandler(connector,
+ EventId.FOCUS, focusRegistration,
+ () -> focusHandlers.addFocusHandler(this));
+ blurRegistration = EventHelper.updateHandler(connector,
+ EventId.BLUR, blurRegistration,
+ () -> focusHandlers.addBlurHandler(this));
+ } else {
+ focusRegistration = EventHelper.updateHandler(connector, this,
+ EventId.FOCUS, focusRegistration, FocusEvent.getType(),
+ widget);
+ blurRegistration = EventHelper.updateHandler(connector, this,
+ EventId.BLUR, blurRegistration, BlurEvent.getType(),
+ widget);
+ }
}
@Override
getRpc().blur();
}
+ /**
+ * Remove all handlers from the widget and the connector.
+ */
+ public void removeHandlers() {
+ if (focusRegistration != null) {
+ focusRegistration.removeHandler();
+ }
+ if (blurRegistration != null) {
+ blurRegistration.removeHandler();
+ }
+ if (stateChangeRegistration != null) {
+ stateChangeRegistration.removeHandler();
+ }
+ }
+
private FocusAndBlurServerRpc getRpc() {
return connector.getRpcProxy(FocusAndBlurServerRpc.class);
}
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import com.google.gwt.aria.client.Roles;
+import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.HasAllFocusHandlers;
+import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FocusWidget;
-import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.HasEnabled;
-import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.WidgetUtil;
+import com.vaadin.client.widgets.ChildFocusAwareFlowPanel;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.ListingJsonConstants;
* @since 8.0
*/
public class VCheckBoxGroup extends Composite implements Field, ClickHandler,
- com.vaadin.client.Focusable, HasEnabled {
+ com.vaadin.client.Focusable, HasEnabled, HasAllFocusHandlers {
public static final String CLASSNAME = "v-select-optiongroup";
public static final String CLASSNAME_OPTION = "v-select-option";
* <p>
* For internal use only. May be removed or replaced in the future.
*/
- public Panel optionsContainer;
+ private ChildFocusAwareFlowPanel optionsContainer;
private boolean htmlContentAllowed = false;
private List<BiConsumer<JsonObject, Boolean>> selectionChangeListeners;
public VCheckBoxGroup() {
- optionsContainer = new FlowPanel();
+ optionsContainer = new ChildFocusAwareFlowPanel();
initWidget(optionsContainer);
optionsContainer.setStyleName(CLASSNAME);
optionsToItems = new HashMap<>();
* Build all the options
*/
public void buildOptions(List<JsonObject> items) {
- /*
- * In order to retain focus, we need to update values rather than
- * recreate panel from scratch (#10451). However, the panel will be
- * rebuilt (losing focus) if number of elements or their order is
- * changed.
- */
-
- Roles.getRadiogroupRole().set(getElement());
- optionsContainer.clear();
- for (JsonObject item : items) {
- String itemHtml = item
- .getString(ListingJsonConstants.JSONKEY_ITEM_VALUE);
- if (!isHtmlContentAllowed()) {
- itemHtml = WidgetUtil.escapeHTML(itemHtml);
+ Roles.getGroupRole().set(getElement());
+ int i = 0;
+ int widgetsToRemove = optionsContainer.getWidgetCount() - items.size();
+ if (widgetsToRemove < 0) {
+ widgetsToRemove = 0;
+ }
+ List<Widget> remove = new ArrayList<>(widgetsToRemove);
+ for (Widget widget : optionsContainer) {
+ if (i < items.size()) {
+ updateItem((VCheckBox) widget, items.get(i), false);
+ i++;
+ } else {
+ remove.add(widget);
}
- VCheckBox checkBox = new VCheckBox();
+ }
+ remove.stream().forEach(this::remove);
+ while (i < items.size()) {
+ updateItem(new VCheckBox(), items.get(i), true);
+ i++;
+ }
+ }
- String iconUrl = item
- .getString(ListingJsonConstants.JSONKEY_ITEM_ICON);
- if (iconUrl != null && iconUrl.length() != 0) {
- Icon icon = client.getIcon(iconUrl);
- itemHtml = icon.getElement().getString() + itemHtml;
- }
+ private void remove(Widget widget) {
+ optionsContainer.remove(widget);
+ optionsToItems.remove(widget);
+ }
- checkBox.addStyleName(CLASSNAME_OPTION);
- checkBox.addClickHandler(this);
- checkBox.setHTML(itemHtml);
- checkBox.setValue(item
- .getBoolean(ListingJsonConstants.JSONKEY_ITEM_SELECTED));
- setOptionEnabled(checkBox, item);
+ private void updateItem(VCheckBox widget, JsonObject item,
+ boolean requireInitializations) {
+ String itemHtml = item
+ .getString(ListingJsonConstants.JSONKEY_ITEM_VALUE);
+ if (!isHtmlContentAllowed()) {
+ itemHtml = WidgetUtil.escapeHTML(itemHtml);
+ }
- optionsContainer.add(checkBox);
- optionsToItems.put(checkBox, item);
+ String iconUrl = item.getString(ListingJsonConstants.JSONKEY_ITEM_ICON);
+ if (iconUrl != null && iconUrl.length() != 0) {
+ Icon icon = client.getIcon(iconUrl);
+ itemHtml = icon.getElement().getString() + itemHtml;
}
+
+ widget.setHTML(itemHtml);
+ widget.setValue(
+ item.getBoolean(ListingJsonConstants.JSONKEY_ITEM_SELECTED));
+ setOptionEnabled(widget, item);
+
+ if (requireInitializations) {
+ widget.addStyleName(CLASSNAME_OPTION);
+ widget.addClickHandler(this);
+ optionsContainer.add(widget);
+ }
+ optionsToItems.put(widget, item);
}
@Override
@Override
public void focus() {
- Iterator<Widget> iterator = optionsContainer.iterator();
- if (iterator.hasNext()) {
- ((Focusable) iterator.next()).setFocus(true);
- }
+ optionsContainer.focus();
}
public boolean isHtmlContentAllowed() {
return (Registration) () -> selectionChangeListeners
.remove(selectionChanged);
}
+
+ @Override
+ public HandlerRegistration addFocusHandler(FocusHandler handler) {
+ return optionsContainer.addFocusHandler(handler);
+ }
+
+ @Override
+ public HandlerRegistration addBlurHandler(BlurHandler handler) {
+ return optionsContainer.addBlurHandler(handler);
+ }
}
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.connectors.AbstractListingConnector;
import com.vaadin.client.data.DataSource;
+import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.VCheckBoxGroup;
import com.vaadin.shared.data.selection.MultiSelectServerRpc;
import com.vaadin.shared.data.selection.SelectionModel;
public class CheckBoxGroupConnector
extends AbstractListingConnector<SelectionModel<?>> {
+ private ConnectorFocusAndBlurHandler handler;
+
@Override
protected void init() {
super.init();
getWidget().addSelectionChangeHandler(this::selectionChanged);
+ handler = ConnectorFocusAndBlurHandler.addHandlers(this);
+ }
+
+ @Override
+ public void onUnregister() {
+ super.onUnregister();
+ handler.removeHandlers();
+ handler = null;
}
private void selectionChanged(JsonObject changedItem, Boolean selected) {
public CheckBoxGroupState getState() {
return (CheckBoxGroupState) super.getState();
}
+
}
--- /dev/null
+/*
+ * Copyright 2000-2016 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.client.widgets;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.dom.client.Style.OutlineStyle;
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.HasAllFocusHandlers;
+import com.google.gwt.event.shared.HandlerManager;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.FocusWidget;
+import com.google.gwt.user.client.ui.Focusable;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ui.FocusableFlowPanel;
+
+/**
+ * Focusable flow panel which fires focus/blur events if it or any of its child
+ * is focused/blured, but doesn't fire events if it happens between its content
+ * (child) elements.
+ *
+ * @author Vaadin Ltd
+ *
+ */
+public class ChildFocusAwareFlowPanel extends FocusableFlowPanel
+ implements HasAllFocusHandlers {
+
+ private class FocusBlurHandler implements BlurHandler, FocusHandler {
+
+ private boolean blurOccured;
+
+ @Override
+ public void onBlur(BlurEvent event) {
+ blurOccured = true;
+ Scheduler.get().scheduleDeferred(() -> fireBlurEvent(event));
+ }
+
+ @Override
+ public void onFocus(FocusEvent event) {
+ if (!blurOccured) {
+ // no blur occured before this focus event
+ eventBus.fireEvent(event);
+ } else {
+ // blur occured before this focus event
+ // another component inside the panel was
+ // blurred => do not fire the focus and set blurOccured to
+ // false, so
+ // blur will not be fired, too
+ blurOccured = false;
+ }
+ }
+
+ private void fireBlurEvent(BlurEvent event) {
+ if (blurOccured) {
+ eventBus.fireEvent(event);
+ blurOccured = false;
+ }
+ }
+ }
+
+ private final HandlerManager eventBus;
+
+ private final FocusBlurHandler handler = new FocusBlurHandler();
+
+ private final Map<Widget, HandlerRegistration> focusRegistrations = new HashMap<>();
+ private final Map<Widget, HandlerRegistration> blurRegistrations = new HashMap<>();
+
+ /**
+ * Creates a new panel instance.
+ */
+ public ChildFocusAwareFlowPanel() {
+ eventBus = new HandlerManager(this);
+ getElement().getStyle().setOutlineStyle(OutlineStyle.NONE);
+ super.addFocusHandler(handler);
+ super.addBlurHandler(handler);
+ }
+
+ @Override
+ public void add(Widget widget) {
+ super.add(widget);
+ addHandlers(widget);
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ focusRegistrations.clear();
+ blurRegistrations.clear();
+ }
+
+ @Override
+ public void insert(Widget widget, int beforeIndex) {
+ super.insert(widget, beforeIndex);
+ addHandlers(widget);
+ }
+
+ @Override
+ public boolean remove(int index) {
+ Widget widget = getWidget(index);
+ boolean isRemoved = super.remove(index);
+ if (isRemoved) {
+ removeHandlers(widget);
+ }
+ return isRemoved;
+ }
+
+ @Override
+ public boolean remove(Widget widget) {
+ boolean isRemoved = super.remove(widget);
+ if (isRemoved) {
+ removeHandlers(widget);
+ }
+ return isRemoved;
+ }
+
+ @Override
+ public HandlerRegistration addFocusHandler(FocusHandler handler) {
+ return eventBus.addHandler(FocusEvent.getType(), handler);
+ }
+
+ @Override
+ public HandlerRegistration addBlurHandler(BlurHandler handler) {
+ return eventBus.addHandler(BlurEvent.getType(), handler);
+ }
+
+ @Override
+ public void focus() {
+ Iterator<Widget> iterator = iterator();
+ if (iterator.hasNext()) {
+ Widget widget = iterator.next();
+ if (widget instanceof Focusable) {
+ ((Focusable) widget).setFocus(true);
+ }
+ }
+ }
+
+ private void addHandlers(Widget widget) {
+ if (focusRegistrations.containsKey(widget)) {
+ assert blurRegistrations.containsKey(widget);
+ return;
+ }
+ if (widget instanceof FocusWidget) {
+ HandlerRegistration focusRegistration = ((FocusWidget) widget)
+ .addFocusHandler(handler);
+ HandlerRegistration blurRegistration = ((FocusWidget) widget)
+ .addBlurHandler(handler);
+ focusRegistrations.put(widget, focusRegistration);
+ blurRegistrations.put(widget, blurRegistration);
+ }
+ }
+
+ private void removeHandlers(Widget widget) {
+ HandlerRegistration focusRegistration = focusRegistrations
+ .remove(widget);
+ if (focusRegistration != null) {
+ focusRegistration.removeHandler();
+ }
+ HandlerRegistration blurRegistration = blurRegistrations.remove(widget);
+ if (blurRegistration != null) {
+ blurRegistration.removeHandler();
+ }
+ }
+
+}
public VOptionGroup() {
super(CLASSNAME);
panel = (Panel) optionsContainer;
- optionsToKeys = new HashMap<CheckBox, String>();
- optionsEnabled = new HashMap<CheckBox, Boolean>();
+ optionsToKeys = new HashMap<>();
+ optionsEnabled = new HashMap<>();
wasMultiselect = isMultiselect();
}
* rebuilt (losing focus) if number of elements or their order is
* changed.
*/
- HashMap<String, CheckBox> keysToOptions = new HashMap<String, CheckBox>();
+ HashMap<String, CheckBox> keysToOptions = new HashMap<>();
for (Map.Entry<CheckBox, String> entry : optionsToKeys.entrySet()) {
keysToOptions.put(entry.getValue(), entry.getKey());
}
- ArrayList<Widget> existingwidgets = new ArrayList<Widget>();
- ArrayList<Widget> newwidgets = new ArrayList<Widget>();
+ ArrayList<Widget> existingwidgets = new ArrayList<>();
+ ArrayList<Widget> newwidgets = new ArrayList<>();
// Get current order of elements
for (Widget wid : panel) {
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
-import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
+import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcDecorator;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.shared.MouseEventDetails;
}
};
- FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(
- this) {
- @Override
- protected void fireEvent(Event event) {
- CheckBox.this.fireEvent(event);
- }
- };
-
/**
* Creates a new checkbox.
*/
public CheckBox() {
registerRpc(rpc);
- registerRpc(focusBlurRpc);
+ registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent));
setValue(Boolean.FALSE);
}
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
-import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
+import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcDecorator;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.v7.data.Container;
public class NativeSelect extends AbstractSelect
implements FieldEvents.BlurNotifier, FieldEvents.FocusNotifier {
- FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(
- this) {
-
- @Override
- protected void fireEvent(Event event) {
- NativeSelect.this.fireEvent(event);
- }
- };
-
public NativeSelect() {
super();
- registerRpc(focusBlurRpc);
+ registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent));
}
public NativeSelect(String caption, Collection<?> options) {
super(caption, options);
- registerRpc(focusBlurRpc);
+ registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent));
}
public NativeSelect(String caption, Container dataSource) {
super(caption, dataSource);
- registerRpc(focusBlurRpc);
+ registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent));
}
public NativeSelect(String caption) {
super(caption);
- registerRpc(focusBlurRpc);
+ registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent));
}
@Override
import java.io.Serializable;
import java.lang.reflect.Method;
+import com.vaadin.server.SerializableConsumer;
import com.vaadin.shared.EventId;
import com.vaadin.shared.Registration;
import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
}
}
+ /**
+ * Focus and blur server RPC implementation which fires focus or blur event
+ * using a provided event handler.
+ *
+ * @author Vaadin Ltd
+ *
+ */
+ public static class FocusAndBlurServerRpcDecorator
+ extends FocusAndBlurServerRpcImpl {
+
+ private final SerializableConsumer<Event> eventHandler;
+
+ /**
+ * Create a new decorator instance.
+ *
+ * @param component
+ * the source events component
+ * @param eventHandler
+ * the event handler to delegate event firing
+ */
+ public FocusAndBlurServerRpcDecorator(Component component,
+ SerializableConsumer<Event> eventHandler) {
+ super(component);
+ this.eventHandler = eventHandler;
+ }
+
+ @Override
+ protected void fireEvent(Event event) {
+ eventHandler.accept(event);
+ }
+ }
+
}
--- /dev/null
+/*
+ * Copyright 2000-2016 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.server;
+
+import java.io.Serializable;
+import java.util.function.Consumer;
+
+/**
+ * A {@link Consumer} that is also {@link Serializable}.
+ *
+ * @see {@link Consumer}
+ * @param <T>
+ * the type of the first argument to the operation
+ *
+ * @since 8.0
+ * @author Vaadin Ltd
+ *
+ */
+@FunctionalInterface
+public interface SerializableConsumer<T> extends Consumer<T>, Serializable {
+ // Only method inherited from Consumer
+}
*/
package com.vaadin.ui;
-import java.util.Objects;
-
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.BlurNotifier;
-import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
+import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcDecorator;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.event.FieldEvents.FocusNotifier;
implements Focusable, FocusNotifier, BlurNotifier {
protected AbstractFocusable() {
- registerRpc(new FocusAndBlurServerRpcImpl(this) {
- @Override
- protected void fireEvent(Event event) {
- AbstractFocusable.this.fireEvent(event);
- }
- });
+ registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent));
}
@Override
import com.vaadin.event.FieldEvents;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
-import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
+import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcDecorator;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.shared.MouseEventDetails;
}
};
- FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(
- this) {
- @Override
- protected void fireEvent(Event event) {
- CheckBox.this.fireEvent(event);
- }
- };
-
/**
* Creates a new checkbox.
*/
public CheckBox() {
registerRpc(rpc);
- registerRpc(focusBlurRpc);
+ registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent));
setValue(Boolean.FALSE);
}
import java.util.Collection;
import com.vaadin.data.Listing;
+import com.vaadin.event.FieldEvents.BlurEvent;
+import com.vaadin.event.FieldEvents.BlurListener;
+import com.vaadin.event.FieldEvents.BlurNotifier;
+import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcDecorator;
+import com.vaadin.event.FieldEvents.FocusEvent;
+import com.vaadin.event.FieldEvents.FocusListener;
+import com.vaadin.event.FieldEvents.FocusNotifier;
import com.vaadin.server.SerializablePredicate;
import com.vaadin.server.data.DataSource;
+import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.optiongroup.CheckBoxGroupState;
/**
* @author Vaadin Ltd
* @since 8.0
*/
-public class CheckBoxGroup<T> extends AbstractMultiSelect<T> {
+public class CheckBoxGroup<T> extends AbstractMultiSelect<T>
+ implements FocusNotifier, BlurNotifier {
/**
* Constructs a new CheckBoxGroup with caption.
* @see Listing#setDataSource(DataSource)
*/
public CheckBoxGroup() {
+ registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent));
}
/**
SerializablePredicate<T> itemEnabledProvider) {
super.setItemEnabledProvider(itemEnabledProvider);
}
+
+ @Override
+ public Registration addFocusListener(FocusListener listener) {
+ addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
+ FocusListener.focusMethod);
+ return () -> removeListener(FocusEvent.EVENT_ID, FocusEvent.class,
+ listener);
+ }
+
+ @Override
+ @Deprecated
+ public void removeFocusListener(FocusListener listener) {
+ removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
+ }
+
+ @Override
+ public Registration addBlurListener(BlurListener listener) {
+ addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
+ BlurListener.blurMethod);
+ return () -> removeListener(BlurEvent.EVENT_ID, BlurEvent.class,
+ listener);
+ }
+
+ @Override
+ @Deprecated
+ public void removeBlurListener(BlurListener listener) {
+ removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
+ }
}
import com.vaadin.event.FieldEvents;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
-import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
+import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcDecorator;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.server.KeyMapper;
}
};
- private FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(
- this) {
- @Override
- protected void fireEvent(Component.Event event) {
- ComboBox.this.fireEvent(event);
- }
- };
-
private String filterstring;
/**
*/
private void init() {
registerRpc(rpc);
- registerRpc(focusBlurRpc);
+ registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent));
addDataGenerator((T data, JsonObject jsonObject) -> {
jsonObject.put(DataCommunicatorConstants.NAME,
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.BlurNotifier;
-import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
+import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcDecorator;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.event.FieldEvents.FocusNotifier;
super();
registerRpc(rpc);
- registerRpc(focusBlurRpc);
+ registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent));
// expand horizontally by default
setWidth(100, UNITS_PERCENTAGE);
private TabsheetServerRpcImpl rpc = new TabsheetServerRpcImpl();
- private FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(
- this) {
-
- @Override
- protected void fireEvent(Event event) {
- TabSheet.this.fireEvent(event);
- }
- };
-
/**
* Replaces a component (tab content) with another. This can be used to
* change tab contents or to rearrange tabs. The tab position and some
--- /dev/null
+/*
+ * Copyright 2000-2016 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.tests.components.checkboxgroup;
+
+import java.util.stream.IntStream;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.CheckBoxGroup;
+
+/**
+ * @author Vaadin Ltd
+ *
+ */
+public class CheckBoxGroupFocusBlur extends AbstractTestUIWithLog {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ CheckBoxGroup<Integer> group = new CheckBoxGroup<>();
+ group.setItems(IntStream.range(1, 10).mapToObj(Integer::valueOf)
+ .toArray(Integer[]::new));
+ addComponent(group);
+
+ group.addFocusListener(event -> log("Focus Event"));
+ group.addBlurListener(event -> log("Blur Event"));
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 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.tests.components.checkboxgroup;
+
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.testbench.customelements.CheckBoxGroupElement;
+import com.vaadin.testbench.elements.LabelElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+/**
+ * @author Vaadin Ltd
+ *
+ */
+public class CheckBoxGroupFocusBlurTest extends MultiBrowserTest {
+
+ @Test
+ public void focusBlurEvents() {
+ openTestURL();
+
+ List<WebElement> checkBoxes = $(CheckBoxGroupElement.class).first()
+ .findElements(By.tagName("input"));
+ checkBoxes.get(0).click();
+
+ // Focus event is fired
+ Assert.assertTrue(logContainsText("1. Focus Event"));
+
+ checkBoxes.get(1).click();
+ // click on the second checkbox doesn't fire anything
+ Assert.assertFalse(logContainsText("2."));
+
+ // click in the middle between the first and the second (inside group).
+ WebElement first = checkBoxes.get(0);
+ int middle = (first.getLocation().y + first.getSize().height
+ + checkBoxes.get(1).getLocation().y) / 2;
+ new Actions(getDriver()).moveByOffset(first.getLocation().x, middle)
+ .click().build().perform();
+ // no new events
+ Assert.assertFalse(logContainsText("2."));
+
+ // click to label of a checkbox
+ $(CheckBoxGroupElement.class).first().findElements(By.tagName("label"))
+ .get(2).click();
+ // no new events
+ Assert.assertFalse(logContainsText("2."));
+
+ // click on log label => blur
+ $(LabelElement.class).first().click();
+ // blur event is fired
+ Assert.assertTrue(logContainsText("2. Blur Event"));
+
+ checkBoxes.get(3).click();
+ // Focus event is fired
+ Assert.assertTrue(logContainsText("3. Focus Event"));
+
+ // move keyboard focus to the next checkbox
+ checkBoxes.get(3).sendKeys(Keys.TAB);
+ // no new events
+ Assert.assertFalse(logContainsText("4."));
+
+ // select the next checkbox
+ checkBoxes.get(4).sendKeys(Keys.SPACE);
+ // no new events
+ Assert.assertFalse(logContainsText("4."));
+ }
+}