Skip to content

Commit

Permalink
Implement focus/blur listeners for NativeSelect.
Browse files Browse the repository at this point in the history
Fixes vaadin/framework8-issues#332

Change-Id: I19996ea83ed1fbe2b115d92d6be5e6a5e158f283
  • Loading branch information
Denis Anisimov committed Oct 31, 2016
1 parent c276c9d commit 2501312
Show file tree
Hide file tree
Showing 9 changed files with 281 additions and 70 deletions.
@@ -0,0 +1,56 @@
/*
* 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.connectors;

import com.google.gwt.event.dom.client.HasAllFocusHandlers;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.shared.data.selection.SelectionModel;

/**
* Abstract class for listing widget connectors that contains focusable children
* to track their focus/blur events.
*
* @author Vaadin Ltd
*
* @param <WIDGET>
* widget type which has to allow to register focus/blur handlers
* @param <SELECTIONMODEL>
* the client-side selection model type
*/
public abstract class AbstractFocusableListingConnector<WIDGET extends Widget & HasAllFocusHandlers, SELECTIONMODEL extends SelectionModel<?>>
extends AbstractListingConnector<SELECTIONMODEL> {

private ConnectorFocusAndBlurHandler handler;

@Override
protected void init() {
handler = ConnectorFocusAndBlurHandler.addHandlers(this);
}

@Override
public void onUnregister() {
super.onUnregister();
handler.removeHandlers();
handler = null;
}

@SuppressWarnings("unchecked")
@Override
public WIDGET getWidget() {
return (WIDGET) super.getWidget();
}
}
44 changes: 10 additions & 34 deletions client/src/main/java/com/vaadin/client/ui/VCheckBoxGroup.java
Expand Up @@ -23,19 +23,14 @@
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.FocusWidget;
import com.google.gwt.user.client.ui.HasEnabled;
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.client.widgets.FocusableFlowPanelComposite;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.ListingJsonConstants;

Expand All @@ -47,8 +42,8 @@
* @author Vaadin Ltd.
* @since 8.0
*/
public class VCheckBoxGroup extends Composite implements Field, ClickHandler,
com.vaadin.client.Focusable, HasEnabled, HasAllFocusHandlers {
public class VCheckBoxGroup extends FocusableFlowPanelComposite implements
Field, ClickHandler, com.vaadin.client.Focusable, HasEnabled {

public static final String CLASSNAME = "v-select-optiongroup";
public static final String CLASSNAME_OPTION = "v-select-option";
Expand All @@ -60,24 +55,14 @@ public class VCheckBoxGroup extends Composite implements Field, ClickHandler,
*/
public ApplicationConnection client;

/**
* Widget holding the different options (e.g. ListBox or Panel for radio
* buttons) (optional, fallbacks to container Panel)
* <p>
* For internal use only. May be removed or replaced in the future.
*/
private ChildFocusAwareFlowPanel optionsContainer;

private boolean htmlContentAllowed = false;

private boolean enabled;
private boolean readonly;
private List<BiConsumer<JsonObject, Boolean>> selectionChangeListeners;

public VCheckBoxGroup() {
optionsContainer = new ChildFocusAwareFlowPanel();
initWidget(optionsContainer);
optionsContainer.setStyleName(CLASSNAME);
getWidget().setStyleName(CLASSNAME);
optionsToItems = new HashMap<>();
selectionChangeListeners = new ArrayList<>();
}
Expand All @@ -88,12 +73,12 @@ public VCheckBoxGroup() {
public void buildOptions(List<JsonObject> items) {
Roles.getGroupRole().set(getElement());
int i = 0;
int widgetsToRemove = optionsContainer.getWidgetCount() - items.size();
int widgetsToRemove = getWidget().getWidgetCount() - items.size();
if (widgetsToRemove < 0) {
widgetsToRemove = 0;
}
List<Widget> remove = new ArrayList<>(widgetsToRemove);
for (Widget widget : optionsContainer) {
for (Widget widget : getWidget()) {
if (i < items.size()) {
updateItem((VCheckBox) widget, items.get(i), false);
i++;
Expand All @@ -109,7 +94,7 @@ public void buildOptions(List<JsonObject> items) {
}

private void remove(Widget widget) {
optionsContainer.remove(widget);
getWidget().remove(widget);
optionsToItems.remove(widget);
}

Expand All @@ -135,7 +120,7 @@ private void updateItem(VCheckBox widget, JsonObject item,
if (requireInitializations) {
widget.addStyleName(CLASSNAME_OPTION);
widget.addClickHandler(this);
optionsContainer.add(widget);
getWidget().add(widget);
}
optionsToItems.put(widget, item);
}
Expand All @@ -161,7 +146,7 @@ public void onClick(ClickEvent event) {
}

public void setTabIndex(int tabIndex) {
for (Widget anOptionsContainer : optionsContainer) {
for (Widget anOptionsContainer : getWidget()) {
FocusWidget widget = (FocusWidget) anOptionsContainer;
widget.setTabIndex(tabIndex);
}
Expand All @@ -185,7 +170,7 @@ protected void setOptionEnabled(VCheckBox checkBox, JsonObject item) {

@Override
public void focus() {
optionsContainer.focus();
getWidget().focus();
}

public boolean isHtmlContentAllowed() {
Expand Down Expand Up @@ -227,13 +212,4 @@ public Registration addSelectionChangeHandler(
.remove(selectionChanged);
}

@Override
public HandlerRegistration addFocusHandler(FocusHandler handler) {
return optionsContainer.addFocusHandler(handler);
}

@Override
public HandlerRegistration addBlurHandler(BlurHandler handler) {
return optionsContainer.addBlurHandler(handler);
}
}
11 changes: 5 additions & 6 deletions client/src/main/java/com/vaadin/client/ui/VNativeSelect.java
Expand Up @@ -17,26 +17,25 @@

import java.util.Objects;

import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.event.dom.client.HasAllFocusHandlers;
import com.google.gwt.user.client.ui.ListBox;
import com.vaadin.client.widgets.FocusableFlowPanelComposite;

/**
* The client-side widget for the {@code NativeSelect} component.
*
* @author Vaadin Ltd.
*/
public class VNativeSelect extends Composite {
public class VNativeSelect extends FocusableFlowPanelComposite
implements HasAllFocusHandlers {

private final ListBox listBox = new ListBox();

/**
* Creates a new {@code VNativeSelect} instance.
*/
public VNativeSelect() {
FlowPanel panel = new FlowPanel();
panel.add(listBox);
initWidget(panel);
getWidget().add(listBox);
}

/**
Expand Down
Expand Up @@ -18,7 +18,7 @@

import com.google.gwt.event.shared.HandlerRegistration;
import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.connectors.AbstractListingConnector;
import com.vaadin.client.connectors.AbstractFocusableListingConnector;
import com.vaadin.client.data.DataSource;
import com.vaadin.client.ui.VNativeSelect;
import com.vaadin.shared.Range;
Expand All @@ -41,8 +41,8 @@
* @since 8.0
*/
@Connect(com.vaadin.ui.NativeSelect.class)
public class NativeSelectConnector
extends AbstractListingConnector<SelectionModel.Single<?>> {
public class NativeSelectConnector extends
AbstractFocusableListingConnector<VNativeSelect, SelectionModel.Single<?>> {

private HandlerRegistration selectionChangeRegistration;
private Registration dataChangeRegistration;
Expand All @@ -67,11 +67,6 @@ public void onUnregister() {
selectionChangeRegistration = null;
}

@Override
public VNativeSelect getWidget() {
return (VNativeSelect) super.getWidget();
}

@Override
public void setDataSource(DataSource<JsonObject> dataSource) {
if (dataChangeRegistration != null) {
Expand Down
Expand Up @@ -22,9 +22,8 @@
import java.util.List;

import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.connectors.AbstractListingConnector;
import com.vaadin.client.connectors.AbstractFocusableListingConnector;
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;
Expand All @@ -36,23 +35,13 @@

@Connect(CheckBoxGroup.class)
// We don't care about the framework-provided selection model at this point
public class CheckBoxGroupConnector
extends AbstractListingConnector<SelectionModel<?>> {

private ConnectorFocusAndBlurHandler handler;
public class CheckBoxGroupConnector extends
AbstractFocusableListingConnector<VCheckBoxGroup, SelectionModel<?>> {

@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) {
Expand Down Expand Up @@ -90,11 +79,6 @@ private void updateOptionGroup() {
getWidget().buildOptions(items);
}

@Override
public VCheckBoxGroup getWidget() {
return (VCheckBoxGroup) super.getWidget();
}

@Override
public CheckBoxGroupState getState() {
return (CheckBoxGroupState) super.getState();
Expand Down
@@ -0,0 +1,58 @@
/*
* 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 com.google.gwt.event.dom.client.BlurHandler;
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;

/**
* Focusable composite whose widget is {@link ChildFocusAwareFlowPanel} (flow
* panel that tracks focus/blur events from its children).
*
* @author Vaadin Ltd
*
*/
public abstract class FocusableFlowPanelComposite extends Composite
implements HasAllFocusHandlers {

private final ChildFocusAwareFlowPanel panel;

/**
* Creates a new instance.
*/
protected FocusableFlowPanelComposite() {
panel = new ChildFocusAwareFlowPanel();
initWidget(panel);
}

@Override
protected final ChildFocusAwareFlowPanel getWidget() {
return (ChildFocusAwareFlowPanel) super.getWidget();
}

@Override
public HandlerRegistration addFocusHandler(FocusHandler handler) {
return panel.addFocusHandler(handler);
}

@Override
public HandlerRegistration addBlurHandler(BlurHandler handler) {
return panel.addBlurHandler(handler);
}
}

0 comments on commit 2501312

Please sign in to comment.